mass_assignment_authorizer和嵌套属性

时间:2011-02-07 20:28:40

标签: ruby-on-rails

根据这篇文章我正在使用动态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的字段,包括用于创建新Employees的空白字段。我找不到在这种情况下调用Employee#accessible=的方法。浏览ActiveRecord源代码,似乎这可能是不可能的:在非常深的调用堆栈的最远端,嵌套关联只会导致使用属性调用Employee.new

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

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

2 个答案:

答案 0 :(得分:2)

我是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会这样做),您将无法使用它。 / p>

我希望有所帮助。

答案 1 :(得分:1)

在我看来,这似乎可以直接从类的控制器代码中为此请求设置。 E.g。

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