Prevent an ActiveRecord attribute from being changed after creation

Updated . Posted . Visible to the public.

Sometimes you can make your life easier by not allowing a record attribute to be changed after the record was created. An example for this is when your model represents a child node in a composition Show archive.org snapshot and has logic that is hard to support for cases when the container changes.

Here is an example for a container Region composed of many children of type Holiday. After saving a Holiday it caches the current number of holidays in its region:

class Region < ActiveRecord::Base

  has_many :holidays
  validates_numericality_of :holiday_count

end

class Holiday < ActiveRecord::Base

  belongs_to :region
  after_save :update_holiday_count_in_region
  after_destroy :update_holiday_count_in_region

  private

  def update_holiday_count
    region.update_attribute :holiday_count, region.holidays.count
  end
  
end

Note that there are probably better days to implement the holiday_count mechanism, but humor me for the sake of the example.

The #update_holiday_count method in the code above has a bug when a holiday's region changes. Only the new region is updated with the current holiday count, while we would actually have to update both the old and new region.

While you can write #update_holiday_count in a way that supports a region change, you can also use the attached Modularity Show archive.org snapshot trait to forbid #region_id from being changed after the Holiday was created:

class Holiday < ActiveRecord::Base

  belongs_to :region
  does 'frozen_attribute', :region_id

  # ...

end

The attached trait will add a validation error if #region_id is changed during an update.

Henning Koch
Last edit
Keywords
freeze, forbid
License
Source code in this card is licensed under the MIT License.
Posted by Henning Koch to makandra dev (2011-03-24 10:06)