Reputation: 2563
I have a very common situation and a solution, but I would like to ask the Rails experts out there if it can be improved.
I have a very typical RESTful controller where the user supplies some of the object attributes upon creation. There is a thing
model, a ThingsController
and various views, including new
, create
, and a _form
partial.
A thing has two attributes,
I’m happy with the approach for dealing with an attribute like the description that that a user specifies in the form, but less confident about the way that I handle an attribute that is passed through via the URL parameters associated with the first click.
This is what I am doing right now (note that I have omitted error checking to simplify matters). First, my new
and create
methods in the controller are as follows:
def new
@thing = Thing.new
@thing.color = Color. find(params[:color])
end
def create
@thing = Thing.new(params[:thing])
@thing.color = Color. find(params[:color])
if @thing.save
flash[:notice] = "Successfully created thing."
redirect_to somewhere_url
else
render :action => 'new'
end
end
The new
view just invokes the _form
partial, which looks as follows:
<% form_for @thing do |f| %>
<%= f.error_messages %>
<%= hidden_field_tag "color", @thing.color.id %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.submit "Submit" %>
<% end %>
It seems a little messy to be passing the color ID through to the create
method as a URL parameter by putting a hidden field in the form. Does this look reasonable, or is there another approach that would be better?
Upvotes: 2
Views: 363
Reputation: 3419
Normally in this situation, I would put a hidden field in the form, which will hold the color_id. The nice thing about this way is that you can get by with just setting the color of the object before you render the form. So your controller changes to:
def new
@thing = Thing.new
@thing.color = Color. find(params[:color])
end
def create
@thing = Thing.new(params[:thing])
if @thing.save
flash[:notice] = "Successfully created thing."
redirect_to somewhere_url
else
render :action => 'new'
end
end
and your form will change to
<% form_for @thing do |f| %>
<%= f.error_messages %>
<%= f.hidden_field :color_id %>
<%= f.label :description %>
<%= f.text_area :description %>
<%= f.submit "Submit" %>
<% end %>
The color is then passed through both forms, and you only need to retrieve the color in the first form. (Don't forget to add validations your Thing model to make sure it has a valid color though).
Upvotes: 3