I'm learning rails (and ruby) and I'd like to know if it is possible to pass a variable between controller functions.
Basically, my problem could be resumed like this:
#controller.rb
def pageA
#assuming @variable is from a form
@variable = "foo"
if @variable == "foo"
redirect_to action: 'pageB'
else
...
end
end
def pageB
#I'd like to reuse @variable in pageB.html.erb
end
Is it possible using redirect_to ? Should I take another approach ?
Out of curiosity, is this a problem that can be resolve using a cache ?
You're thinking about this at too low of a level.
Variables are just a tool that you use to point to data in memory when processing a request and do not persist reliably between one request to another. They are never a valid part of an end goal.
Instance variables do not persist between requests as the requests are not processed by the same controller instance.
Rather you need to think of it in terms of passing state (or references to it) back and forth between the server and client. HTTP provides several mechanisms for this such as the URI, request body and headers.
Data that needs to be persisted between requests on the server needs to be stored somewhere such as a database. In that case we don't need to pass the actual data. We just need to tell the server what we are looking for.
In the typical Rails REST setup state (in the form of resources) are saved in the database and then you just redirect to that resource.
class ThingController < ApplicationController
# Displays a form to create a new resource
# GET /things/new
def new
@thing = Things.new
end
# Responds to form submissions
# POST /things
def create
@thing = Thing.new(thing_params)
if @thing.save
redirect_to @thing # redirect to /things/:id
else
render :new # renders the form again
end
end
# Shows a member of the collection
# GET /things/1
def show
@thing = Thing.find(params[:id])
end
private
def thing_params
params.require(:thing)
.permit(:foo, :bar)
end
end
Here we just pass the id of the record as part of the URL and can use that in the next request to fetch the newly created record.
Note that a typical Rails noob trap is to try to use a redirect for "failed" form submissions:
def create
@thing = Thing.new(thing_params)
@my_var= 'Hello World'
if @thing.save
redirect_to @thing, my_param: @my_var # redirect to /things/:id
else
redirect_to action: :new # OMG How do I pass all the data along?
end
end
If the user tries to create/update a resource with invalid data just render the form again and send it as a response instead.
If you really need to pass additional data from the server along with a redirect you can use query string parameters:
# Responds to form submissions
# POST /things
def create
@thing = Things.new(thing_params)
@my_var = 'Hello World'
if @thing.save
redirect_to @thing, my_param: @my_var # redirect to /things/:id
else
render :new # renders the form again
end
end
# Shows a member of the collection
# GET /things/1
def show
@my_var = params[:my_param]
@thing = Thing.find(params[:id])
end
Any additional options passed to redirect_to
(with the exception of named options like status
, notice
, alert
) will be added to the URL as query string parameters. While there certainly are valid use cases ask yourself if you really need it first and take safety into consideration.
If you need a more transparent mechanism to pass state to a browser and have it send it back cookies can be used. Rails provides the session mechanism that can be used to store data in cookies in a higher level way.
Out of curiosity, is this a problem that can be resolve using a cache ?
Not really.
A cache is a way to improve performance by storing data that is expensive to produce. Any cache that is user specific still needs a mechanism to identify the user.