1

是否可以将 mongoid 配置field为反序列化为 aStruct而不是 a Hash?(有默认值

我的用例:一家公司的订阅计划在我的模型中存储为哈希。

以前作为哈希

class Company
  include Mongoid::Document
  field :subscription, type: Hash, default: {
      ends_at: 0,
      quantity: 0,
      started_at: 0,
      cancelled: false,
    }

我希望我不必写Company.first.subscription[:ends_at],我宁愿写Company.subscription.ends_at

我想像下面这样会更好

class Company
  include Mongoid::Document
  field :subscription_plan, type: Struct, default: Struct.new(
    :ends_at, :quantity, :started_at, :cancelled
  ) do
    def initialize(
      ends_at: nil, 
      quantity: 0,
      starts_at: nil,
      cancelled: false
    ); super end
  end
end

如果计划可以在一个类中定义就更好了

class SubscriptionPlan < Struct.new(
  ends_at, :quantity, :starts_at, :cancelled
) do
  def initialize(
  ends_at: nil, 
  quantity: 0,
  starts_at: nil,
  cancelled: false
); super; end
end

class Company
  field :subscription_plan, type: SubscriptionPlan, default: SubscriptionPlan.new
end

我怎样才能使它工作?

4

2 回答 2

1

对此持保留态度,因为我从未使用过 MongoDB 或 Mongoid。尽管如此,谷歌搜索“自定义类型”还是让我看到了这个文档

这是自定义类型示例的改编版本:

class SubscriptionPlan

  attr_reader :ends_at, :quantity, :started_at, :cancelled

  def initialize(ends_at = 0, quantity = 0, started_at = 0, cancelled = false)
    @ends_at = ends_at
    @quantity = quantity
    @started_at = started_at
    @cancelled = cancelled
  end

  # Converts an object of this instance into a database friendly value.
  def mongoize
    [ends_at, quantity, started_at, cancelled]
  end

  class << self

    # Get the object as it was stored in the database, and instantiate
    # this custom class from it.
    def demongoize(array)
      SubscriptionPlan.new(*array)
    end

    # Takes any possible object and converts it to how it would be
    # stored in the database.
    def mongoize(object)
      case object
      when SubscriptionPlan then object.mongoize
      when Hash then SubscriptionPlan.new(object.values_at(:ends_at, :quantity, :started_at, :cancelled)).mongoize
      else object
      end
    end

    # Converts the object that was supplied to a criteria and converts it
    # into a database friendly form.
    def evolve(object)
      case object
      when SubscriptionPlan then object.mongoize
      else object
      end
    end
  end
end

class Company
  include Mongoid::Document
  field :subscription, type: SubscriptionPlan, default: SubscriptionPlan.new
end

这应该让你更接近你想做的事情。

请注意,默认值SubscriptionPlan将由每个具有默认值的公司共享。如果您修改一家公司的默认计划,可能会导致一些奇怪的错误。

于 2017-01-29T15:13:00.733 回答
0

我意识到我只是在重新实现一个没有 ID 的嵌套文档。最后,我决定为我的 . 切换到一个普通的嵌入式文档subscription,因为有一个额外的 ID 字段不是问题,而且我得到了 mongoid 范围作为奖励。Mongoid::Attributes::Dynamic如果我想支持任何键,我可以随时添加。

然而,对于想要创建自己的类型的人来说,这个问题和其他答案仍然是相关的。

于 2017-02-07T15:49:57.017 回答