开发者

Rails 3 devise, current_user is not accessible in a Model ?

in my project.rb model, I'm trying to create a scope with a dynamic variable:

scope :instanceprojects, lambda { 
    where("projects.instance_id = ?", current_user.instance_id)
} 

I get the following error:

undefined local variable or method `current_user' for #<Class:0x102fe3af0>

Where in the controller I can ac开发者_开发百科cess current_user.instance_id... Is there a reason the model can't access it and a way to get access? Also, is this the right place to create a scope like the above, or does that belong in the controller?


This doesn't make much sense, as you already pointed. The current_user doesn't belong to model logic at all, it should be handled on the controller level.

But you can still create scope like that, just pass the parameter to it from the controller:

scope :instanceprojects, lambda { |user|
    where("projects.instance_id = ?", user.instance_id)
} 

Now you can call it in the controller:

Model.instanceprojects(current_user)


The already accepted answer provides a really correct way to achieve this.

But here's the thread-safe version of User.current_user trick.

class User
  class << self
    def current_user=(user)
      Thread.current[:current_user] = user
    end

    def current_user
      Thread.current[:current_user]
    end
  end
end

class ApplicationController
  before_filter :set_current_user

  def set_current_user
    User.current_user = current_user
  end
end

This works as expected, however it can be considered dirty, because we basically define a global variable here.


Ryan Bates lays out a pretty safe way to implement this kind of strategy in this railscast

You can browse the source code here

Here he creates a current_tenant method, but you could easily substitute current_user instead.

Here are the key bits of code...

#application_controller.rb
around_filter :scope_current_tenant

private

def current_tenant
  Tenant.find_by_subdomain! request.subdomain
end
helper_method :current_tenant

def scope_current_tenant
  Tenant.current_id = current_tenant.id
  yield
ensure
  Tenant.current_id = nil
end

#models/tenant.rb

def self.current_id=(id)
  Thread.current[:tenant_id] = id
end

def self.current_id
  Thread.current[:tenant_id]
end

Then in the model you can do something like...

default_scope { where(tenant_id: Tenant.current_id) }


You don't need to use scopes. If you have set the appropriate associations in models, following piece of code placed in controller should do the trick:

@projects = current_user.instance.projects
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜