Ruby-on-rails Rails 3 设计,在模型中无法访问 current_user ?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3742785/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 23:13:45  来源:igfitidea点击:

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

ruby-on-railsactiverecordruby-on-rails-3

提问by AnApprentice

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? Also, is this the right place to create a scope like the above, or does that belong in the controller?

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

回答by mdrozdziel

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)

回答by Micha? Szajbe

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

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

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

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

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

回答by Mark Locklear

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_tenantmethod, but you could easily substitute current_userinstead.

在这里,他创建了一个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) }

回答by sampi

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