在我的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
...模型是否有理由无法访问它以及获取访问权限的方法?此外,这是创建上述范围的正确位置,还是属于控制器?
答案 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