在 Rails 上有条件地包含基于模型实例 Ruby 的模块

Conditionally Include a Module based on the Instance of a Model Ruby on Rails

在我正在开发的 rails 应用程序中,我有一个订单模型,订单在技术上有 2 种类型(报纸和网络),但它们都在订单模型中表示。 Order下面的children根据Order的类型不同,因此获取订单数据的方法也不同。

我有一个 CurrentMonthsOrders 序列化程序,我希望能够在其中调用:

 order.start_date
 order.end_date

无需检查我正在处理的订单类型。所以我希望能够做的是根据我正在处理的订单类型包含模块。 possible/is 这是解决这个问题的最佳方法吗?

以下是模块:

  module WebOrder

    def start_date
      web_line_items.sort_by(&:start_date).first.start_date
    end

    def end_date
      web_line_items.sort_by(&:end_date).last.end_date
    end

  end

  module Newspaper

    def start_date
      newspaper_placements.last.date.strftime('%m/%d')
    end

    def end_date
      object.newspaper_placements.first.date.strftime('%Y/%-m/%-d')
    end

  end

通常,在 Rails 中,这种数据模型将通过单一 Table 继承(通常缩写为 STI)来完成。您将有一个订单 class(以及数据库中相应的 orders table),它会有一个 type 列。然后,您将为 WebOrder 和 Newspaper 定义 Order 的 subclasses:

class WebOrder < Order
  def start_date
    ...
  end

  ...
end

class Newspaper < Order
  ...
end

当 WebOrder 或 Newspaper 订单保存到数据库时,Rails 将在 type 列中记录 class,当从数据库中提取记录时,Rails 将使用 type 列创建正确子 class.

的实例

可以将模块的方法添加到 class 的特定实例,但我通常不推荐这样做,因为这样你具有表面上相同 class,但具有不同 code/behavior 的对象。此外,它会导致更高的内存使用量,因为您要自定义许多单独的对象。但如果你要这样做,它的工作原理大致如下:

 order = Order.new
 order.extend(Newspaper)

不过,您必须记住在加载 Order 实例和调用自定义方法之间的某个时间执行此操作。如果您使用单一 Table 继承,Rails 会为您处理。

Single Table Inheritance 在这里有一个很好的解释:http://eewang.github.io/blog/2013/03/12/how-and-when-to-use-single-table-inheritance-in-rails/