简体   繁体   English

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

[英]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: 在我的project.rb模型中,我正在尝试使用动态变量创建一个范围:

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 access current_user.instance_id ... Is there a reason the model can't access it and a way to get access? 控制器中的哪个位置我可以访问current_user.instance_id ...模型是否有理由无法访问它以及获取访问权限的方法? 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. current_user根本不属于模型逻辑,应该在控制器级别处理。

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

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 Ryan Bates 在这个railscast中提出了一种非常安全的方法来实现这种策略

This a paid episode (don't down vote me!) but you can browse the source code for free 这是付费剧集(不要向我投票!)但您可以免费浏览源代码

Here he creates a current_tenant method, but you could easily substitute current_user instead. 在这里,他创建了一个current_tenant方法,但您可以轻松替换current_user

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM