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.