How Variables Flow from Controller to View
Assuming we have the following files:
# config/routes.rb Rails.application.routes.draw do get 'pokemons/:id', to: 'pokemons#show' end
# app/models/pokemon.rb class Pokemon < ApplicationRecord has_one :trainer end
# app/models/trainer.rb class Trainer < ApplicationRecord end
# app/controllerspokemons_controller.rb class PokemonsController < ApplicationController def show @pokemon = pokemon.find_by(id: params[:id]) @trainer = if @pokemon @pokemon.trainer else nil end end end
# app/views/pokemons/show.html.erb <h3>My Pokemon</h3> <p><%= @pokemon&.name %>(trainer: <%= @trainer&.name %>)</p>
Per GoRails, how variables in an action of a controller are passed to View can be thought as the following:
# Pseudo code; NOT how Rails actually runs # Assuming we have records for pokemons/trainers in DB: ## When a HTTP request knocks on our Rails app's door with the url, ## "yourdomain.com/pokemons/1"... # 1. ## Route calls a certain action of a controller according to its routing setup kontroller = PokemonsController.new kontroller.send(:show) # 2. ## Now we have the following ## since we have instance variables set via "show" method kontroller.instance_variables # [:@pokemon, :@trainer] # 3. ## When no explicit "render()" stated in the method, Rails by default calls ## the template with matching name to the action ## See: ## https://guides.rubyonrails.org/layouts_and_rendering.html#rendering-by-default-convention-over-configuration-in-action ## https://youtu.be/mRJSovhdzWc?t=146 (Sending Data Between Rails Controllers and Views by GoRails) def show # ..omitted render 'show.html.erb', kontroller.instance_variables end
<!-- 4. The final product, "show.html", from show.html.erb --> <h3>My Pokemon</h3> <p>Pikachu(trainer: Dannyboi)</p>
# When Rails receives some other request... instance = SomeOtherController.new
Description of the Steps (*not how Rails actually runs)
When a HTTP request comes into Rails and enters its Route…
- On the inside, Rails creates a new instance of the controller and calls a certain method (or “action”, in terms of MVC model), “show”
- Now the instance has the instance variables in the method “show”
- At the end of the action method it calls
render()to bind variables in the ERB template (see default rendering in controllers) with instance variables that we just created
- Variables in ERB template are now filled in and the template gets “translated” into HTML
Why not just the Local Variables, but Instance Variables for Controller’s Actions?
Local variables can NOT be accessed outside of the method like instance variables do
From the illustration above, variables must still be accessible out of its containing method’s scope, so they can be used in ERB template.
Consider the examples below. In
Ex. 1, the value of the instance variable
@var is still accessible outside of the
bar method, where in
Ex. 2, the value assigned from local
var can’t be found beyond the scope of
# Ex. 1 class Foo attr_reader :var def bar @var = 'bar' end end i = Foo.new i.send(:bar) p i.var # outputs "bar"
# Ex. 2 class Foo attr_reader :var def baz var = 'baz' end end i = Foo.new i.send(:baz) p i.var # outputs nil, instead of "baz"
Disclaimer: The above serves as reference of my understanding to Rails ONLY and the actual flow is yet to verified.