3

我正在尝试跟踪用户当前、以前和选择的(期末更改)订阅状态。

在每月周期结束时,如果chosen_subscription != current_subscription,则current_subscription更改。

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 希望我以一种对我来说没有意义的方式详细说明这一点:

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.

当我覆盖现有的 current_subscription 时会发生这种情况。我想,此时 Mongoid 想注销旧订阅的用户订阅。

当然,每个订阅对象只属于一个用户,并且user == user.previous_subscription.user == user.current_subscription.user == user.chosen_subscription.user

Subscription然而,说这user与三者中的任何一个相反,对我来说是没有意义的。

我应该如何正确构建它?

4

2 回答 2

6

正如它所说:您必须添加一个 :inverse_of 选项。试试这个:

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
于 2013-08-16T16:58:34.840 回答
0

每个 mongoid 关系都有一个逆关系,用于正确设置双方。大多数情况下,它可以根据命名约定、使用的类等正确识别,但有时您需要明确定义它们。

mongoid 在这里抱怨的问题是Usermodel 中定义的关系不明确,因为 mongoid 无法识别它们中的哪些映射subscription.userSubscription. 此外,当subscription.user = some_user使用时,mongoid 无法识别您是否需要设置previous_subscriptioncurrent_subscriptionchosen_subscription在用户中订阅对象。即使您没有显式调用此方法,您也可能会遇到这些问题,因为 mongoid 在设置关系时会尝试设置逆。

我不确定这是否是构建系统的正确方法,但您可以inverse_of: nil在关系中定义以告诉 mongoid 在设置关系时不要设置逆关系。subscription.user=仅当您从不需要在代码中使用时才应使用此方法。subscription.user也可能有问题,但是可以使用未记录的方法doc._parent,或者doc._root如果您绝对需要它们。这种方法虽然解决了问题,但也有其不足之处。我试图用以下代码在这里展示它们:

class Tester
  include Mongoid::Document

  field :name, type: String

  embeds_one :first_module, class_name: 'TestModule', inverse_of: nil
  embeds_one :last_module, class_name: 'TestModule', inverse_of: nil

end

class TestModule
  include Mongoid::Document

  field :name, type: String

  # not needed as such, but required to tell mongoid that this is a embedded document
  embedded_in :tester, inverse_of: nil
end

t1 = Tester.new(name: 't1')
m1 = t1.build_first_module(name: 't1m1')
m2 = t1.build_last_module(name: 't1m2')

t1.first_module == m1 #=> true
t1.last_module == m2  #=> true

m1.tester             #=> nil
m2.tester             #=> nil 

t1.save
t1 = Tester.last
m1 = t1.first_module
m2 = t1.last_module

t1.first_module == m1 #=> true
t1.last_module == m2  #=> true

m1.tester             #=> nil
m2.tester             #=> nil

在 mongoid 问题跟踪器上也有一些关于这样的讨论:#1677 & #3086

于 2013-08-18T11:24:02.273 回答