【问题标题】:mass_assignment_authorizer and nested attributesmass_assignment_authorizer 和嵌套属性
【发布时间】:2011-02-07 20:28:39
【问题描述】:

根据这篇文章,我正在使用动态attr_accessible

http://asciicasts.com/episodes/237-dynamic-attr-accessible

它工作正常。但是我还没有找到一种优雅的方法来使它与嵌套属性一起工作。下面是一些简化的代码:

class Company < ActiveRecord::Base
  has_many :employees

  accepts_nested_attributes_for :employees
end

class Employee < ActiveRecord::Base
  belongs_to :company

  attr_protected :salary

  attr_accessor :accessible

  def mass_assignment_authorizer  
    if accessible == :all
      ActiveModel::MassAssignmentSecurity::BlackList.new
    else
      super + (accessible || [])
    end
  end 
end

假设我有一个带有公司 RESTful 表单的管理界面。在此表单上,我有 employees_attributes 的字段,包括用于创建新员工的空白字段。在这种情况下,我找不到调用Employee#accessible= 的方法。浏览 ActiveRecord 源代码,这似乎是不可能的:在非常深的调用堆栈的最远端,嵌套关联只会导致使用属性调用 Employee.new

我曾考虑创建一个可以通过批量分配传递的特殊属性。如果属性的值是正确的代码,Employee 实例会将@accessible 设置为:all。但我认为没有办法保证在受保护的属性之前设置此属性。

有没有办法让动态受保护的属性与嵌套属性一起工作?

【问题讨论】:

    标签: ruby-on-rails


    【解决方案1】:

    我是 Rails 新手,在尝试让嵌套属性自己工作时遇到了很多麻烦,但我发现我必须将嵌套属性添加到我的可访问列表中。

    class Company < ActiveRecord::Base
      has_many :employees
    
      accepts_nested_attributes_for :employees
    
      attr_accessible :employees_attributes
    end
    

    我的理解是accepts_nested_attributes_for 创建了那个特殊的employees_attributes,但是当您将所有属性默认为不可访问(我相信 asciicast 会这样做)时,您将无法使用它。

    希望对你有帮助。

    【讨论】:

    • 是的,您必须将employees_attributes 添加到您的可访问属性列表中。但真正的问题是在员工对象本身上设置“可访问”属性。请注意,根据问题开头引用的文章,这仅在您使用 dynamic 可访问属性时相关。
    【解决方案2】:

    在我看来,这就像可以直接从您的控制器代码中针对该请求设置的类。例如

    Employee.accessible = :all
    Company.create(params[:company])
    Employee.accessible = nil
    

    可以提取到像这样的块

    def with_accessible(*types)
      types.flatten!
      types.each{|type| type.accessible = :all}
      yield
      types.each{|type| type.accessible = nil}
    end
    

    所以你的最终控制器代码是

    with_accessible(Employee, OtherClass, YetAnotherClass) do
      Company.create(params[:company])
    end
    

    很好地表达了所有属性的情况

    对于只有某些属性的情况,我可能会修改如下

    def with_accessible(*types, &block)
      types.flatten!
      return with_accessible_hash(types.first, &block) if types.first.is_a?(Hash)
      types.each{|type| type.accessible = :all}
      ret = yield
      types.each{|type| type.accessible = nil}
      ret
    end
    
    def with_accessible_hash(hash, &block)
      hash.each_pair do |klass, accessible|
        Object.const_get(klass).accessible = accessible
      end
      ret = yield
      hash.keys.each{|type| type.accessible = nil}
      ret
    end
    

    这给了你

    with_accessible(:Employee => [:a, :b, :c], :OtherClass => [:a, :b]) do
      Company.create(params[:company])
    end
    

    【讨论】:

      猜你喜欢
      • 2013-01-02
      • 2013-07-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多