I’ve been knocking my head against a problem for ages until I realised what was going on.
I want to have a committee which must always have at least one member. To achieve this, each member checks it’s not the last member before being destroyed.
The code below should prevent the last member being destroyed UNLESS the committee itself is being destroyed in which case it happily self-destructs.
class Committee < ActiveRecord::Base
has_many :committee_members
before_destroy: { @destroy_initiated = true }
def destroy_initiated?
@destroy_initiated
end
end
class CommitteeMember < ActiveRecord::Base
belongs_to :committee
before_destroy :ensure_not_last
def ensure_not_last
unless self.committee.destroy_initiated?
if self.committee.committee_members.count == 1
raise 'You cannot remove the last committe member. Try destroying the committee instead'
end
end
end
end
The problem
The problem is that each CommitteeMember references a different instance of the Committee object, they all have different object identities:
e.g. #<Committee:0x00000105c41f20> v. #<Committee:0x00000105c2c3a0>
This means that even when I set @destroy_initiated to be true on once instance of Committee with ID 20, it’s not going to be set to true on the instance referenced by one of its committee_members.
Leaving aside Rails 3.1 which I know has an identity map, is there a clean workaround to having an instance variable which is available on all instantiations of Committee?
I’m considering doing a class variable containing a map of destroy_initiated? to each Committee ID but this feels pretty messy.
I’m not sure if I can answer this question properly without more context, but I can give you a possible solution to think about…
In an app I just recently put in production, we would essentially cache an object as an instance variable on ApplicationController. Then whenever we needed it, we simply ask for the instance variable rather than finding it with Active Record.
So now, for the duration of the request, anything inheriting from ApplicationController can access the @committee object. If you can use a similar pattern (doesn’t have to be application controller, could just be any other controller) you would essentially have a “global” variable for the duration of the request.