Mass_assignment_authorizer and nested attributes

I am using dynamic attr_accessible as per this article:

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

It works great. But I did not find an elegant way to make it work with nested attributes. Here is some simplified code:

 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 

Say I have an admin interface with a RESTful form for a company. In this form, I have fields for employees_attributes , including empty fields for creating new employees. I cannot find a way to call Employee#accessible= in this context. Looking through the source code of ActiveRecord, it seems that this may not be possible: in the farthest part of a very deep call stack, nested associations simply lead to calling Employee.new with attributes.

I was thinking of creating a special attribute that could be passed through mass assignment. If the attribute value was the correct code, the Employee instance would set @accessible to :all . But I don’t think there is a way to guarantee that this attribute will be set before protected attributes.

Is there a way to make dynamically protected attributes work with nested attributes?

+6
ruby-on-rails
source share
2 answers

It seems to me something that can be set directly from your controller code in the class for this request. For example.

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

What can be extracted into a block like

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

So your final controller code

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

Pretty expressively what happens for all attributes

In the case of only certain attributes, I can change it to the following

 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 

What gives you

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

I'm new to rails and I had loading problems that tried to make nested attributes work on their own, but I found that I needed to add nested attributes to the list of available ones.

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

I understand that accepts_nested_attributes_for creates this special employees_attributes , but when you by default all attributes are not available (which I consider as an ascecast), you cannot use it.

I hope this helps.

+2
source share

All Articles