Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mongoid embedding one class as multiple fields

I'm trying to track a user's current, previous and chosen (changes at end of period) subscription states.

At the end of the monthly period, if chosen_subscription != current_subscription, the current_subscription gets changed.

class User
  include Mongoid::Document

  embeds_one :previous_subscription, class_name: "Subscription"
  embeds_one :current_subscription, class_name: "Subscription"
  embeds_one :chosen_subscription, class_name: "Subscription"
end

class Subscription
  include Mongoid::Document

  embedded_in :user

  field :plan, type: String
  field :credits, type: Integer
  field :price_per_credit, type: BigDecimal

  field :start, type: Date
  field :end, type: Date
end

Mongoid wants me to specify this more and in a way that does not make sense to me:

Mongoid::Errors::AmbiguousRelationship:

Problem:
  Ambiguous relations :previous_subscription, :current_subscription, :chosen_subscription defined on User.
Summary:
  When Mongoid attempts to set an inverse document of a relation in memory, it needs to know which relation it belongs to. When setting :user, Mongoid looked on the class Subscription for a matching relation, but multiples were found that could potentially match: :previous_subscription, :current_subscription, :chosen_subscription.
Resolution:
  On the :user relation on Subscription you must add an :inverse_of option to specify the exact relationship on User that is the opposite of :user.

This happens when I overwrite an existing current_subscription. I suppose, at this moment, Mongoid wants to unregister the old subscription's user's subscription.

Of course, every subscription object only belongs to one user and the user == user.previous_subscription.user == user.current_subscription.user == user.chosen_subscription.user

Yet it does not make sense to me to tell Subscription that user is inverse of any one of the three.

How should I build it right?

like image 464
Jan Avatar asked Mar 28 '26 01:03

Jan


1 Answers

As it says: you must add an :inverse_of option. Try this:

class User
  include Mongoid::Document

  embeds_one :previous_subscription, class_name: "Subscription", inverse_of: :previous_subscription
  embeds_one :current_subscription, class_name: "Subscription", inverse_of: :current_subscription
  embeds_one :chosen_subscription, class_name: "Subscription", inverse_of: :chosen_subscription
end

class Subscription
  include Mongoid::Document

  embedded_in :user, inverse_of: :previous_subscription
  embedded_in :user, inverse_of: :current_subscription
  embedded_in :user, inverse_of: :chosen_subscription

  field :plan, type: String
  field :credits, type: Integer
  field :price_per_credit, type: BigDecimal

  field :start, type: Date
  field :end, type: Date
end
like image 118
hawk Avatar answered Mar 29 '26 16:03

hawk