【问题标题】:Owner-filtered model objects on Rails 3Rails 3 上的所有者过滤模型对象
【发布时间】:2012-05-27 16:38:37
【问题描述】:

我需要对我的 ActiveRecord 模型进行一些过滤,我想通过 owner_id 过滤我的所有模型对象。我需要的基本上是 ActiveRecord 的 default_scope。

但我需要通过模型无法访问的会话变量进行过滤。我读过some solutions,但没有一个有效,基本上他们中的任何一个都说你可以在声明 default_scope 时使用 session。

这是我对范围的声明:

class MyModel < ActiveRecord::Base
    default_scope { where(:owner_id => session[:user_id]) }
    ...
end

很简单,对吧?但它没有说 方法会话不存在

希望你能帮忙

【问题讨论】:

  • 您是否有理由不想要具有关联的所有者对象?
  • 嗯....好点,明天我会测试它,我现在没时间了。感谢您的回复

标签: ruby-on-rails ruby-on-rails-3 session default-scope


【解决方案1】:

您将无法将其合并到 default_scope 中。由于没有会话,这将破坏(例如)控制台内的所有使用。

你可以做什么:添加一个方法来做你的 ApplicationController 像这样

class ApplicationController
  ...
  def my_models
    Model.where(:owner_id => session[:user_id])
  end
  ...

  # Optional, for usage within your views:
  helper_method :my_models
end

这个方法无论如何都会返回一个作用域。

【讨论】:

    【解决方案2】:

    与会话相关的过滤是一项 UI 任务,因此它在控制器中占有一席之地。 (模型类无权访问请求周期、会话、cookie 等)。

    你想要的是

    # my_model_controller.rb
    before_filter :retrieve_owner_my_models, only => [:index] # action names which need this filtered retrieval
    
    def retrieve_owner_my_models
       @my_models ||=  MyModel.where(:owner_id => session[:user_id])
    end
    

    由于当前用户的所有权过滤是一个典型的场景,也许你可以考虑使用标准的解决方案,比如搜索'cancan gem,accessible_by'

    还要注意 default_scope 的弊端。 rails3 default_scope, and default column value in migration

    【讨论】:

    • 恕我直言,这不是 default_scope 的替代品:创建新对象时,它没有建立 owner_id,在进行复杂搜索时,它不会按 owner_id 自动过滤... default_scope更加自动化。
    • 1. MVC 设计中的业务逻辑与 UI 分离,即模型可以在没有会话的 UI-s 中使用。因此,将所有权分配给登录用户是控制器的责任。 2) default_scope 的自动所有者过滤是糟糕的设计:例如,当您实际操作 MyModel-s 时,管理界面会检索所有所有者或部分代码的产品。 3. default_scope 最好用于设置自然顺序和默认状态(:active => true),但即使这些也最好在控制器、初始化程序和数据库模式中完成。在我看来,这使得 rails default_scope 存在争议。
    【解决方案3】:

    模型中的会话对象被认为是不好的做法,相反,您应该向 User 类添加一个类属性,该类属性是您在 ApplicationController 中的 around_filter 中设置的,基于 current_user

    class User < ActiveRecord::Base
    
        #same as below, but not thread safe
        cattr_accessible :current_id
    
        #OR
    
        #this is thread safe
        def self.current_id=(id)
          Thread.current[:client_id] = id
        end
    
        def self.current_id
          Thread.current[:client_id]
        end  
    
    end
    

    在你的ApplicationController 中做:

    class ApplicationController < ActionController::Base
        around_filter :scope_current_user  
    
        def :scope_current_user
            User.current_id = current_user.id
        yield
        ensure
            #avoids issues when an exception is raised, to clear the current_id
            User.current_id = nil       
        end
    end
    

    现在在您的MyModel 中,您可以执行以下操作:

    default_scope where( owner_id: User.current_id ) #notice you access the current_id as a class attribute
    

    【讨论】:

    • @RubénT.F.太棒了,希望你觉得它有用
    • 线程是指当前线程。在这里检查它的安全性:stackoverflow.com/questions/7896298/…client_idUser 模型的属性,在 default_scope 中使用
    猜你喜欢
    • 2019-07-29
    • 1970-01-01
    • 2021-05-02
    • 1970-01-01
    • 1970-01-01
    • 2013-03-16
    • 1970-01-01
    相关资源
    最近更新 更多