20

I am trying to access an instance variable which is set in the controller in the model. The controller is the products controller and the model is the products model. The instance variable is a instance of another model called account.

The instance variable is @current_account

When I run the code nothing happens, I do not get an error. Does anyone know where I can find something read about access instance variables set in the controller from the model?

Thanks

Eef

1
  • So you're trying to access the @current_account variable in a model? The @current_account variable is being set in a controller? Commented Mar 10, 2010 at 21:26

5 Answers 5

48

You shouldn't generally try to access the controller from the model for high-minded issues I won't go into.

I solved a similar problem like so:

class Account < ActiveRecord::Base
  cattr_accessor :current
end

class ApplicationController < ActionController::Base
  before_filter :set_current_account
  def set_current_account
    #  set @current_account from session data here
    Account.current = @current_account
  end
end

Then just access the current account with Account.current

Sign up to request clarification or add additional context in comments.

5 Comments

Aren't class variables shared across all requests?!
I don't understand how to get the variable value from the :current symbol in the model? I tried Account.current and current.
What's the difference between cattr_accessor and attr_accessor?
cattr_accessor is attached to the class, like self.value, rather than a method value.
@vise to me also seems like a single user web application. I was wondering whether thread_cattr_accessor might be of any help. If we are sure that one thread will not switch between requests back and forth.
10

DISCLAIMER: The following code breaks MVC conventions, that said...

Using class attributes can probably lead to thread safety issues. I would use Thread.current + around_filter to store controller related data at thread level, and ensure it gets cleared just before the request finishes:

class ApplicationController < ActionController::Base

  around_filter :wrap_with_hack

  def wrap_with_hack
    # We could do this (greener solution): 
    # http://coderrr.wordpress.com/2008/04/10/lets-stop-polluting-the-threadcurrent-hash/
    # ... but for simplicity sake:
    Thread.current[:controller] = self
    begin
      yield
    ensure
     # Prevent cross request access if thread is reused later
     Thread.current[:controller] = nil
    end
  end
end

Now the current controller instance will be avaliable globaly during the request processing through Thread.current[:controller]

2 Comments

Hi @ibaixas thanks for this. But can you please explain how will class attribute leads to thread safety issue. I am a newbie. And is this issue present in Rails 4 as well
Class variables are shared between threads. This means that when using a multithreaded app server like puma, different threads handling different requests will store the controller instance in the same variable, overwriting each other. By using the Thread.current hash you ensure that the variable is only set by the current thread. Sorry for the (2 year) delay ...
6

If you need to access a controller variable from a model it generally means your design is wrong because a controller serves as bridge between view and model (at least in Rails), controller gets info from models, models shouldn't know anything about controllers, but if you want to do it anyway you can do it just as jeem said, but I'd rather do:

 class << self

    attr_accessor :current

 end

instead of

cattr_accessor :current

you can see why here => cattr_accessor doesn't work as it should

1 Comment

This is not much better because this is still shared between requests, to say nothing of thread-safety. It should either be an attribute on a User instance or else you should pass it to the methods that need to know it.
4

I can't comment directly so I'll post here: the accepted answer does not seem to be right. As @vise notes, class variables are shared across requests. So unless there's just one current account for the entire app, this won't behave as expected.

For more, see the accepted answer by @molf here: Is Rails shared-nothing or can separate requests access the same runtime variables?

Comments

1

I'm not sure if I understand the question exactly, but I'll take a stab.

I think if you need to access a controller instance variable from the model then you either need to make it an attribute in the model, or move your logic to the other class controller, not model.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.