Reputation: 234
I have two models that are associated by a has_one
relationship. We also have a callback that initializes the association. The classes look (roughly) like this:
class User
has_one :relevance, class_name: 'User::Relevance', inverse_of: :user, dependent: :destroy
after_create :initialize_relevance
def initialize_relevance
self[:relevance] = User::Relevance.new
end
# other garbage that *should* be irrelevant
end
class User::Relevance
belongs_to :user, inverse_of: :relevance, index: true
# more other garbage that *should* be irrelevant
end
Sometimes the relevance association gets into a wonked state where it is nil. When this happens, we want to re-initialize the relationship when it is called and return it instead of nil. So in the class User
, we would have this:
def relevance
self[:relevance] = User::Relevance.new if self[:relevance].nil?
self[:relevance]
end
Except this doesn't work and nil
is still returned. I've also tried the same with update_attribute(User::Relevance.new)
and self.create_relevance
but nil
seems to always be returned. Not really sure where to go from here and would love any ideas. I can also provide more code or examples if it would be helpful.
Additional Details:
relevance
.Upvotes: 0
Views: 100
Reputation: 23347
Instead of setting the association in the callback, you may try to build relevance
in the getter method:
class User
def relevance
self[:relevance] || User::Relevance.new
end
end
This pattern is nicely described here: http://blog.arkency.com/2016/07/always-present-association/
Upvotes: 0
Reputation: 230551
Mongoid supports autobuilding one-to-one relations. This should help (no hooks or getter overrides needed).
has_one :relevance,
class_name: 'User::Relevance',
inverse_of: :user,
dependent: :destroy,
autobuild: true
As the option name hints, relevance
will spring to life upon access (if it was nil before access).
Also, you are aware that this way relevance is not persisted, right?
after_create :initialize_relevance
def initialize_relevance
self[:relevance] = User::Relevance.new
end
So no wonder it returns nil
later on.
Upvotes: 1