JackDanger / immutable_attributes

specify attributes within an ActiveRecord model that can be set but not modified
http://6brand.com
MIT License
24 stars 7 forks source link

Handle ActiveRecord::Base#[]= for immutable attributes #4

Closed nmertaugh closed 13 years ago

nmertaugh commented 13 years ago

The current immutable_attributes head does not handle the ActiveRecord::Base#[]= method that wraps write_attribute as follows:

# File activerecord/lib/active_record/base.rb, line 1529
def []=(attr_name, value)
  write_attribute(attr_name, value)
end

This allows for very easily changing attributes that have been designated immutable:

u = User.create(:immutable_attribute = 'virgin')
u.immutable_attribute = 'muted'
# => ImmutableErrors::ImmutableAttributeError: immutable_attribute is immutable!
u.immutable_attribute
# => 'virgin'
u[:immutable_attribute] = 'muted'
# (no error raised, attributed changed in memory)
u.immutable_attribute
# => 'muted'
u.save
# (no error raised, attributed changed on disk)
u.immutable_attribute
# => 'muted'

I am proposing the handling of this by overwriting the ActiveRecord::Base#[]= method to first check whether the passed attribute has already been declared immutable.

NOTE:

I'm using class_eval with a heredoc here instead of a block. If there is a clean way to pass the args variable from ImmutableAttributes#attr_immutable into the new definition of []= and use a block for class_eval then I am in favor of that.

JackDanger commented 13 years ago

I rarely, if ever, use the Model#[]= method so I hadn't considered this. Thanks for the fix!

I added a test and I took your suggestion of replacing the heredoc with a class_eval block. Good call on that.

I've also added you as an author (https://rubygems.org/gems/immutable_attributes). Thanks for the help!

nmertaugh commented 13 years ago

Excellent, thanks very much Jack! Great gem, I'll definitely be staying involved.