Rails 模型指的是新的假模型

Rails model referring to new fake model

我有以下模型结构,我在其中存储了 Books 和 SellingInfo(代表售前和售后成本):

class Books < ApplicationRecord
  STATUSES = %w[planned purchased].freeze

  has_many :selling_infos, dependent: :destroy
end

class SellingInfo < ApplicationRecord
  belongs_to :book
end

由于 ActiveAdmin 的要求,我想与模型建立新关系,该模型与 selling_infos table(相同的列、类型等)相同,但我只会使用它当 Book.status == 'purchased'。为了不使数据库超载,我不想创建新模型,假设 purchased_selling_info,具有相同的数据结构,但创建某种 'fake model' 并将其用作 purchased_selling_info

我正在尝试将如下内容添加到 Book 模型中:

# models/book.rb
  has_one :purchased_selling_info,
          -> { where(status: 'purchased') },
          class_name: 'SellingInfo',
          dependent: :destroy

但是当我尝试检查它是否在 rails 控制台中工作时,我收到一个错误:

2.7.2 :009 > Book.purchased_selling_info.size

NoMethodError (undefined method `purchased_selling_info' for #<Class:0x00007f9916f33200>)

将具有不同行为的记录存储在一个 table 中的解决方案是 Single Table Inheritance。通过添加 type 列,您可以拥有不同的关联:

class Book < ApplicationRecord
  has_many :selling_infos, dependent: :destroy
end

class PurchasedBook < Book 
  has_one :purchased_selling_info,
          class_name: 'SellingInfo',
          dependent: :destroy
end

当您从数据库中加载记录时,ActiveRecord 会读取继承列(默认情况下为 type)并将初始化 class。

如果您不想使用 STI,您可以通过 custom validations or association callbacks.

限制 purchased_selling_info 的创建
class SellingInfo
  validates :validates_is_purchased, if: ->{ |si| si.purchased? }

  def validates_is_purchased
    errors.add(:book, 'wrong book type')
  end
end

您目前正在做的事情将无法工作,因为:

  1. 将 lambda 添加到关联只是将过滤器应用于关联。关联是 class 级别的,您不能使它们依赖于实例的属性。
  2. Book.purchased_selling_info.size 给出 NoMethod 错误,因为您在 class.
  3. 上调用实例方法

In order not to overload the database I don't want to create new model, let's say purchased_selling_info, with the same data structure but create some kind of 'fake model' and use it as purchased_selling_info.

您应该仔细权衡“使数据库过载”与 hacky 解决方案增加的复杂性和维护成本。对我来说,这听起来像是一个过早优化的案例。