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

时间:2010-09-18 17:47:49

标签: ruby-on-rails activerecord ruby-on-rails-3

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

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

我收到以下错误:

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

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

4 个答案:

答案 0 :(得分:73)

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

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

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

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

Model.instanceprojects(current_user)

答案 1 :(得分:30)

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

但这是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

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

答案 2 :(得分:8)

Ryan Bates提出了一种非常安全的方法来实施这种策略in this railscast

这是一个付费剧集(不要向我投票!)但你可以browse the source code for free

此处他创建了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

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

default_scope { where(tenant_id: Tenant.current_id) }

答案 3 :(得分:0)

您不需要使用范围。如果您在模型中设置了适当的关联,那么放在控制器中的以下代码应该可以解决这个问题:

@projects = current_user.instance.projects