In my application I have a products_controller that makes use of instance variables. My understanding of instance variables in Ruby is that you can use them within different methods of the same class. So why is it that we use the same instance variable in multiple methods of rails apps? Below we have an instance variable @product set twice, is the @product variable in the new action not overwritten when we use it in the create action?
I am just a little confused as to the scope of these variables within methods of the same class.
def new
@product = Product.new
end
def create
@product = Product.new(product_params)
respond_to do |format|
if @product.save
format.html { redirect_to @product, notice: 'Product was successfully created.' }
format.json { render :show, status: :created, location: @product }
else
format.html { render :new }
format.json { render json: @product.errors, status: :unprocessable_entity }
end
end
end
Instance variables are in the instance class scope. In Ruby on Rails, because the way how that API was built, instance variables are also available in the views.
You need to be aware of that new and create methods are commonly used in different ProductsController
instances.
First request: GET http://localhost:3000/product/new
When you ask for the new
action (I suppose that is a form), Rails API implementation at a given point creates an instance of ProductsController
and sends the new
message to that instance (calls the new method). Then, the instance variable @product is created and available in any method, or in any view that the action renders. At a given point, Rails replies with a web page and the class instance, and all its instance variables, are destroyed (won't be available anymore).
Second request: POST http://localhost:3000/product/create
When you submit the form for database persistence, again a new controller instance is created, and the create
method is called. Because is a new instance, the @product doesn't have any value.
Note, however, that there is a difference between rendering a view (like its happening in the new
action) and a redirect (like you do in the create
action if @product.save
is true). When you render, you remain in the same controller instance, with you redirect, new server request happens, so the previous controller instance is destroyed and a new controller instance is created.
The before action
before_action is called before you actually start executing the action code. In Rails perspective, an action is not a Ruby method. The class method is the definition of that action:
From Rails guides:
A controller is a Ruby class which inherits from ApplicationController and has methods just like any other class. When your application receives a request, the routing will determine which controller and action to run, then Rails creates an instance of that controller and runs the method with the same name as the action.
The action acts as an entry point determined by the routes. If you call create inside new, it won't trigger that before_action again.
No, it doesn't overwrite it. An instance variable (@variable_name
) is accessible within all methods of a single instance object of a class.
Now imagine, there's a client request to the "new product route". Rails creates an instance object of your products_controller and invokes only the new
action of that instance. That defines @product = Product.new
, renders your new.html.erb
template and that's it. After that, the controller instance will be forgotten.
Next, your client clicks the "create product button" of your "new product form". Another request arrives the server. Rails creates another instance of your products_controller and calls the create
action. The new
action isn't invoked. And so, you have a new product instance (@product = Product.new(product_params)
) with the attributes sent by the form.
Of course, you could call the create
method from your new
action ...
# only an example
def new
@product = Product.new
create
end
... or the other way round. This would overwrite the @product variable. But why should you do that?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With