Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #6004 (closed defect: fixed)

Opened 2 years ago

Last modified 1 year ago

[PATCH] ActiveRecord::Base#remove_attributes_protected_from_mass_assignment returns nil when both attr_protected and attr_accessible are used

Reported by: notethan@gmail.com Assigned to: David
Priority: normal Milestone:
Component: ActiveRecord Version:
Severity: normal Keywords: attr_protected attr_accessible remove_attributes_protected_from_mass_assignment attributes=
Cc:

Description

ActiveRecord::Base#remove_attributes_protected_from_mass_assignment returns nil when both attr_protected and attr_accessible are used.

for example, with the table:

create_table :foos do |t|
  t.column :bar, :integer
  t.column :baz, :integer
end

and model

class Foo < ActiveRecord::Base
  attr_protected :bar
  attr_accessible :baz
end

anything that calls attributes=, which uses the result of remove_attributes_protected_from_mass_assignment, errors:

>> Foo.new(:bar => 0, :baz => 0)

NoMethodError: You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.each
        from ./vendor/rails/activerecord/lib/active_record/base.rb:1643:in `attributes='
        from ./vendor/rails/activerecord/lib/active_record/base.rb:1482:in `initialize_without_callbacks'
        from ./vendor/rails/activerecord/lib/active_record/callbacks.rb:225:in `initialize'
        from (irb):13

the obvious patch updating the function:

    def remove_attributes_protected_from_mass_assignment(attributes)
      if self.class.accessible_attributes.nil? && self.class.protected_attributes.nil?
        attributes.reject { |key, value| attributes_protected_by_default.include?(key.gsub(/\(.+/, "")) }
      elsif self.class.protected_attributes.nil?
        attributes.reject { |key, value| !self.class.accessible_attributes.include?(key.gsub(/\(.+/, "").intern) || attributes_protected_by_default.include?(key.gsub(/\(.+/, "")) }
      elsif self.class.accessible_attributes.nil?
        attributes.reject { |key, value| self.class.protected_attributes.include?(key.gsub(/\(.+/,"").intern) || attributes_protected_by_default.include?(key.gsub(/\(.+/, "")) }
      else
        attributes.reject { |key, value| self.class.protected_attributes.include?(key.gsub(/\(.+/,"").intern) || !self.class.accessible_attributes.include?(key.gsub(/\(.+/, "").intern) || attributes_protected_by_default.include?(key.gsub(/\(.+/, "")) }
      end
    end

with which for the above test case we get the expected

>> Foo.new(:bar => 0, :baz => 0)
=> #<Foo:0x24b1d44 @new_record=true, @attributes={"baz"=>0, "bar"=>nil}>

Attachments

diff (1.0 kB) - added by anonymous on 09/01/06 04:34:37.
diff with this patch
demonstrate_error_when_using_both_attrprotected_and_attraccessible.diff (2.4 kB) - added by smeade on 01/11/07 20:19:19.
demonstrate_error_when_using_both_attrprotected_and_attraccessible.diff

Change History

09/01/06 04:34:37 changed by anonymous

  • attachment diff added.

diff with this patch

(follow-ups: ↓ 2 ↓ 3 ) 09/03/06 16:00:47 changed by bitsweat

  • status changed from new to closed.
  • resolution set to untested.

Please reopen with tests demonstrating this behavior.

(in reply to: ↑ 1 ) 01/11/07 20:17:20 changed by smeade

  • status changed from closed to reopened.
  • resolution deleted.

Replying to bitsweat:

Please reopen with tests demonstrating this behavior.

reopening to provide tests demonstrating this behavior. But, should it be patched?

Are attr_protected and attr_accessible designed to use together? If accessible attributes are defined, then all others are by definition protected, so listing protected attributes is not DRY (and vise-versa) and would only cause confusion because someone looking at the attr_protected list might think only those listed are protected when in fact, any attribute not listed in attr_accessible is protected.

For example, given:

create_table :foos do |t|
  t.column :bar, :integer
  t.column :baz, :integer
  t.column :bat, :integer
end

and

class Foo < ActiveRecord::Base
  attr_accessible :baz
  attr_protected :bar
end

is :bat protected or accessible? :bat is not listed as accessible, so must be protected. But - :bat is not listed as protected so must be accessible. Maybe a patch to have a warning about this?

Then it is a design decision, should Rails prompt identification of this unexpected combination and still it handle the new anyway?

01/11/07 20:19:19 changed by smeade

  • attachment demonstrate_error_when_using_both_attrprotected_and_attraccessible.diff added.

demonstrate_error_when_using_both_attrprotected_and_attraccessible.diff

(in reply to: ↑ 1 ) 01/11/07 20:21:12 changed by smeade

Replying to bitsweat:

Please reopen with tests demonstrating this behavior.

not sure if you really want old (3 months) tickets re-openned or not. If not, sorry about that, and please just re-close. thnx

05/29/07 20:35:53 changed by bitsweat

  • status changed from reopened to closed.
  • resolution set to fixed.

(In [6896]) Raise an exception if both attr_protected and attr_accessible are declared. Closes #8507, #6004.