Rails 3设计,在模型中无法访问current_user?

AnA*_*ice 46 activerecord ruby-on-rails ruby-on-rails-3

在我的project.rb模型中,我正在尝试使用动态变量创建一个范围:

scope :instanceprojects, lambda { 
    where("projects.instance_id = ?", current_user.instance_id)
} 
Run Code Online (Sandbox Code Playgroud)

我收到以下错误:

undefined local variable or method `current_user' for #<Class:0x102fe3af0>
Run Code Online (Sandbox Code Playgroud)

在控制器中我可以访问的位置current_user.instance_id......模型是否有理由无法访问它以及获取访问权限的方法?此外,这是创建上述范围的正确位置,还是属于控制器?

mdr*_*iel 73

正如你已经指出的那样,这没有多大意义.current_user根本不属于模型逻辑,应该在控制器级别处理.

但你仍然可以创建这样的范围,只需从控制器传递参数:

scope :instanceprojects, lambda { |user|
    where("projects.instance_id = ?", user.instance_id)
} 
Run Code Online (Sandbox Code Playgroud)

现在你可以在控制器中调用它:

Model.instanceprojects(current_user)
Run Code Online (Sandbox Code Playgroud)

  • 我把范围'称为'所以它会很好地阅读.`Project.of current_user` (7认同)
  • @marvin - 使用` - >`参数以不同的方式传递给它 - >(用户){...}` (3认同)

Mic*_*jbe 32

已经接受的答案提供了一种非常正确的方法来实现这一点.

但这是User.current_user技巧的线程安全版本.

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
Run Code Online (Sandbox Code Playgroud)

这按预期工作,但它可以被认为是脏的,因为我们基本上在这里定义一个全局变量.

  • 谢谢 - 我有一个特定的情况我真的需要这个并且无法传递它.顺便说一句,这段代码有一些错误 - 你应该使用ApplicationController的User.current_user =方法(否则,为什么要这样做),以及它也被设置为:current_user,但是读者可以从以下网址读取:用户(我很快就看到了!) (2认同)

Mar*_*ear 8

Ryan Bates 在这个railscast中提出了一种非常安全的方法来实现这种策略

这是付费剧集(不要向我投票!)但您可以免费浏览源代码

在这里,他创建了一个current_tenant方法,但您可以轻松替换current_user.

以下是代码的关键部分......

#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
Run Code Online (Sandbox Code Playgroud)

然后在模型中你可以做类似......

default_scope { where(tenant_id: Tenant.current_id) }
Run Code Online (Sandbox Code Playgroud)