What is the purpose of the new controller action in Rails?
A scaffold generates the new action like this:
def new
@product = Product.new
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @product }
end
end
def create
@product = Product.new(params[:product])
respond_to do |format|
if @product.save
format.html { redirect_to(@product, :notice => 'Product was successfully created.') }
format.xml { render :xml => @product, :status => :created, :location => @product }
else
format.html { render :action => "new" }
format.xml { render :xml =&开发者_运维问答gt; @product.errors, :status => :unprocessable_entity }
end
end
end
and the view renders a partial, named form
. Since the new
form renders with the action set to create a new product, what is the purpose of @product
? I see that the create
action instantiates a new object as well. Is it only used so that you can tie the form to an object, so that everything goes from action to action correctly?
You can think of @product in the new action as being an unsaved object that simply fills out the form fields that are rendered in the view. This makes new.html.erb pretty much the same as edit.html.erb and allows them to share a single partial, _form.html.erb.
When this partial is used in the new action, the fields are populated by a fresh, empty, and unsaved @product object. This is the Product.new that appears in the new action. When the partial is used in the edit action, you've got a @product object that presumably has values for all its attributes. Now, suppose you didn't use @product in the new action. The form used in new.html.erb would need to be different than the form used in edit. Good luck maintaining them if you ever add a new field to the model.
Another advantage of this approach is that you can pre-populate attributes of the new @product before they're rendered in the view. Suppose you want to use the name "new product" as the default name for each product. You can do this in the new action this way:
def new
@product = Product.new(:name => 'new product')
respond_to do |format|
format.html # new.html.erb
format.xml { render :xml => @product }
end
end
One main purpose is so that you can use the same form for new and edit.
The controller passes the @product object (new or existing) and Rails sees whether it's a new record or an existing record. It makes certain decisions based on that such as to pull the record values into the input fields (existing) and which controller action to send the form on submission.
If you have a form_for, the new action is used to properly initialize the @product in form_for @product
, which expects an ActiveRecord model. If I remember correctly, the Product's scope (for any controller action) ends with the request, so the create action has no knowledge of the new action, requiring another Product to be initialized.
The form_for
method uses the @product
variable to correctly assign the form to the resource controller to find the correct URL, id (in the case of an update), and more. You can read about it in section 2.3 of http://guides.rubyonrails.org/form_helpers.html
If you're that concerned about memory usage, you don't have to initialize @product
, but then you would have to manually create your own form without using the nice resource-based form_for
.
精彩评论