views:

3605

answers:

4

I have a form that displays differently depending on the parameter it was called with.

Ex.

testsite.local/users/new?type=client

So if type was a or b, the form would display different fields.

My problem is when the form is filled out incorrectly, because if the user couldn't be saved corrently, it renders the form with the default error messages, but also without my parameter.

testsite.local/users/new

How can I call my render action and pass whatever this parameter is set to to it? So that I can still keep my built-in error messages about why the form couldn't be sumbitted properly AND have it be the right form?

Here's my create action:

def create
   @user = User.new(params[:user])
   roles = params[:user][:assigned_roles]
   if @user.save
     update_user_roles(@user,roles)
     if current_user.is_admin_or_root?
       flash[:message] = "User \"#{@user.username}\" created."
       redirect_to users_path
     else
       flash[:message] = "Congrats! You're now registered!"
       redirect_to app_path
     end
   else
     render :action => 'new'
   end
 end
+1  A: 

Extract for Rails Guides

Using render with :action is a frequent source of confusion for Rails newcomers. The specified action is used to determine which view to render, but Rails does not run any of the code for that action in the controller

I believe your new?type=client is used to setup some kind of variable in your new action? And the variable is later used in your new.html.erb view?

Then you need to change a little bit your create action like this:

  else
     # add code here to setup any variable for type = client
     # and which will be used in your view
     render :action => 'new'
  end
 end
Aurélien Bottazzini
Well, this still breaks the visual consistency of my URL path, such that, upon a failed submission of a form, the url changes from `new?type=client` to just `new`. Is there no way to set the url parameter for the newly rendered action? Or am I still missing something here?
neezer
+1  A: 

You could always force it by:

params[:type] ||= "client"

in your new action in your controller. If type is not set then it will default to client. The URL will not show this however.

Ryan Bigg
Is there now way to have the URL show this?
neezer
+3  A: 

There are two ways to do it.

Either add a hidden field or an extra parameter to the form_for

Adding hidden field in your form containing named type and set it equal to params[:type] this will preserve the type on the render if validation fails.

View code:

<% form_for @user do |f| %>
...
<%= hidden_field_tag :type, params[:type] %>
<%end%>

Adding an extra paramater to the form:

<% form_for @user, create_user_path(@user, :type => params[:type] %>
...
<%end%>

Either one will do what you want it to.

EmFi
+1  A: 

As elucidated by another user answering my other related question, here's what I was after:

form_for @user, :url => { :action => :create, :type => @type }

... which preserves the parameter :type through each new render action (assuming I have it defined correctly in my controller).

neezer