Topic: streamlining code, how can i accomplish this?

I'm trying to streamline my user signup like so but I'm having trouble. I must be a bit off from Rails convention. Here is what I am trying to do:

signup_controller.php:

def index
  if request.get?
    @user = User.new
  else
    @user = User.new(params[:user])
    if @user.save
      SignupMailer.deliver_activate(@user)
      render :template => 'signup/complete'
    end
  end
end

user accesses: /signup
form posts to: /signup

if no form, it will show template: signup/index.rhtml
if form posted, upon successful save, show template: signup/complete.rhtml

this all works, except if the user calls /signup/complete
it renders the complete.rhtml template! i assumed it would not because i have
not written a method in the controller, also if i had a protected method it will
still show!

is there a way to disable this behavior or rework my code to get the same results?

any help appreciated!

Re: streamlining code, how can i accomplish this?

You can set rails to render nothing for the complete action in your controller:

def complete
  render :nothing => true
end

Or you can redirect to another action, raise an exception, etc.

Railscasts - Free Ruby on Rails Screencasts

Re: streamlining code, how can i accomplish this?

Oh, great! I can just redirect to home or something. It works...

It seems like a hackish way to do this though, what would be Rails convention besides
having two separate actions like /signup and /do_signup

Re: streamlining code, how can i accomplish this?

another idea, you could register the user and a flag in the session then use a conditional redirect in your 'complete' method

this is totally untested, but should work (he writes with crossed-fingers!)

def index
# your code as before
if @user.save
  session[:user] = @user
  session[:just_registered] = true
# rest of your method
end

def complete
  redirect_to :action => 'index' unless (session[:user] and session[:just_registered])
  session[:just_registered] = false # only want to show the complete page once
end


the complete template would then display once, and only once after creation of a new user

Re: streamlining code, how can i accomplish this?

If all the complete.rhtml template is doing is showing a short "signup complete" message then I'd suggest using flash[:notice] for this and redirecting to a page which is a little more useful to the user, such as their account page.

def signup
  @user = User.new(params[:user])
  if request.post? && @user.save
    SignupMailer.deliver_activate(@user)
    flash[:notice] = "Signup successful."
    redirect_to :action => 'index' # Of course change this to whatever page you want to redirect to
  end
end

You can then access the flash[:notice] on the resulting page.

If the complete.rhtml contains more than just a "complete" message, such as an account activation thing, then I'd rename it to whatever it does:

def activation
  if request.post?
    # activate account and redirect to another page
  end
end

The activation.rhtml page would contain the activation form with instructions. You can then redirect to this activation action when signup is successful. Does that make sense?

Railscasts - Free Ruby on Rails Screencasts