How do I store an instance variable across multiple actions in a controller?
Not really. Each call to a controller action is stateless. Nothing is available after the controller action finishes. A new controller instance is created for each request, and then discarded at the end of the request.
If you don't want to store it in the session, or database model, you don't have many options if you're wanting that variable to be specific to a particular session.
If it is global across all sessions, you could put it in a @@class_variable
rather than an @instance_variable
, but that can get messy once you start having multiple Rails processes (each which will have their own copy of it), or if you're running in threadsafe mode, you can end up with nasty concurrency bugs.
I guess you could look at something like memcached, but you'd still need to key that to some user_id or other session marker (unless it's global)
Same instance variable for all actions of a controller
Unless you're rendering show.html.erb
from the index
action, you'll need to set @some_instance_variable
in the show action as well. When a controller action is invoked, it calls the matching method -- so the contents of your index
method will not be called when using the show
action.
If you need @some_instance_variable
set to the same thing in both the index
and show
actions, the correct way would be to define another method, called by both index
and show
, that sets the instance variable.
def index
set_up_instance_variable
end
def show
set_up_instance_variable
end
private
def set_up_instance_variable
@some_instance_variable = foo
end
Making the set_up_instance_variable
method private prevents it from being called as a controller action if you have wildcard routes (i.e., match ':controller(/:action(/:id(.:format)))'
)
Rails: Set a common or global instance variable across several controller actions
Firstly, you don't want to try to insert code "between" a controller action and a template rendering. Why? Because you want the controller action to have the freedom to choose what sort of response to give. It could return XML, JSON, headers only, a redirection, nothing, etc. That's why after filters are executed after the response has been rendered.
Secondly, you don't want to monkey patch Fixnum
. I mean, maybe you do, but I don't. Not often at least, and not unless I get some totally wicked semantic benefits from it, like being able to say 3.blind_mice
. Monkey patching it for a random use case like this seems like a maintenance headache down the road.
You mention refactoring out all the controllers' case specific code into a before filter and running them sequentially. Which brings up to my mind... @foo
is the same in every case? If that's the case, then one before filter would work just fine:
before_filter :do_common_stuff
def do_common_stuff
@foo = common_foo
@bar = do_something_with @foo
end
That's a totally legit approach. But if @foo changes from controller to controller... well, you have a few more options.
You can separate your before filters into two halves, and customize one per controller.
# application_controller:
before_filter :get_foo, :do_something_common
def do_something_common
@bar = do_something_with @foo
end
# baz_controller:
def get_foo
@foo = pull_from_mouth
end
#baf_controller:
def get_foo
@foo = pull_from_ear
end
But you know, if it's a simple case that doesn't need database access or network access or anything like that... which your case doesn't... don't kill yourself. And don't sweat it. Throw it in a helper. That's what they're there for, to help. You're basically just rearranging some view data into a form slightly easier to use anyway. A helper is my vote. And you can just name it next_url
. :)
Pass instance variable between controllers using a helper
I found a way of making the contact_id
accesible to the EngagementsController
without having to pass variables from ContactsController
to EngagementsController
via a helper. The nested resources:
resources :contacts do
resources :engagements
end
generates the path:
POST /contacts/:contact_id/engagements(.:format) engagements#create
Thus the contact_id of the engagement is made accessible to the EngagementsController
:
def create
@contact = Contact.find(params[:contact_id])
@engagement = @contact.engagements.build(engagement_params)
end
make variables accessible to multiple actions in controller
Just define them as constant:
class MyController < AplicationController
SETUP_STAGES = [:data_entry_completed, :data_validation_completed]
is it possible to use a variable value across multiple actions
is there any way i can store the
@variable
value when either index or show is called and when next time other action is called just use the same@variable
value and not hit database again?
No, there is no way. When the other action is called, it's a completely different instance of your controller class. And that instance variable from last time, it's long gone.
That aside, you should do what Sebastian suggests. It's a logical continuation of what you started (so that, at least, you don't hit the DB twice in the same action).
We can't achieve that using class instance variables too?
Using class-level data, this is more achievable, but only if you have one web process (so that all requests are guaranteed to use the same class). As soon as you add another web worker, this stops working.
This question made me look at your code again, and I realized that this all is pointless/misguided. :)
@variable = SomeModel.includes(:some_other_model)
This line does not hit database. So it doesn't make sense to try and memoize it. Saves nothing. THIS is what hits the database
@variable = SomeModel.includes(:some_other_model).find_by!(id: params[:id])
^^^^^^^^^^^^^^^^^^^^^^^^^
rails pass params or variable to multiple controller actions
Use a session variable, that's what they're there for...
session[:prid] = params[:prid]
You can even set up a method in your ApplicationController
to give you the principal when you need it...
class ApplicationController < ActionController::Base
def current_principal
principal.find_by(id: session[:prid])
end
end
Now just use current_principal
where you need it. (It'll be nil
if you haven't selected one yet)
Passing instance variable from one form to the a different controller's action in Rails
You'll have two methods on your controller. One for each form (rendered by the associated template). The first form should post to the second action. The second action can then transfer the request parameters into instance variables, to be available within the second template.
class FooController
def bar
# setup instance variables and render first form
end
def baz
@bar_values = params[:bar]
# setup other instance variables and render second form
end
end
UPDATE0 Do it across two controllers using session.
class FooController
def new_baz
# setup instance variables and render the first form
end
def create_baz
# respond to posting of form data
session[:current_baz_values] = params
redirect_to :action => "baq", :controller => "bar"
end
end
class BarController
def baq
@baz_values = session[:current_baz_values]
# setup other instance variables and render the second form
end
end
Related Topics
Authlogic and Multiple Sessions for the Same User
Does Ruby Have Syntax for Safe Navigation Operator of Nil Values, Like in Groovy
How to Stop Rails' Built-In Server from Listening on 0.0.0.0 by Default
How to Get the Current Test Filename from Rspec
Creating a Setter Method That Takes Extra Arguments in Ruby
Generate All "Unique" Subsets of a Set (Not a Powerset)
Retrieve Number from the String Pattern Using Regular Expression
Ruby: Ssl_Connect Syscall Returned=5 Errno=0 State=Unknown State (Openssl::Ssl::Sslerror)
How to Mask All But Last Four Characters in a String
Ruby: Array Contained in Array, Any Order
How to Receive a JSON Object with Rack
Rails 4.1 Activerecord::Relation Is No More Like Array
How to Batch Convert Mp4 Files to Ogg with Ffmpeg Using a Bash Command or Ruby
What Does the Term "Vendoring" or "To Vendor" Mean for Ruby on Rails