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,
- a color, which is set when they hit a link to create it (i.e. a “Create Red Thing” link that encodes the ID of red as a URL parameter)
- a description, which is entered by the user in the form view
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 matt开发者_运维百科ers). 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?
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).
精彩评论