ruby-on-rails - Rails 模型指的是新的假模型
问题描述
我有以下模型结构,我在其中存储了 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
表相同的模型(相同的列、类型等)建立新关系,但我只会在Book.status == 'purchased'
. 为了不使数据库过载,我不想创建新模型,比如说purchased_selling_info
,具有相同的数据结构,但创建某种“假模型”并将其用作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>)
解决方案
将具有不同行为的记录存储在一个表中的解决方案是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
默认情况下)并将初始化该类。
如果您不想使用 STI,您可以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
你目前正在做的事情不会起作用,因为:
- 将 lambda 添加到关联只是将过滤器应用于关联。关联是类级别的,您不能使它们依赖于实例的属性。
Book.purchased_selling_info.size
给出 NoMethod 错误,因为您在类上调用实例方法。
为了不使数据库超载,我不想创建新模型,比如说购买_销售信息,具有相同的数据结构,但创建某种“假模型”并将其用作购买销售信息。
您应该仔细权衡“重载数据库”与 hacky 解决方案增加的复杂性和维护成本。对我来说,这听起来像是一个过早优化的案例。
推荐阅读
- windows - Bind9 DNS 服务器无法在 Windows 11 上运行
- laravel - Laravel 从一个类别及其所有子类别中获取所有帖子
- laravel-backpack - 如何创建具有两个字段的字段?
- c# - FluentMigrator - 限制外部程序集中的一些功能
- r - 趋势线未显示在散点图中
- express - express-session 不在 CORS 客户端域中存储 cookie
- python - 'Wave_read' 对象在 Python 中没有属性 'read'
- hadoop - hadoop distcp 从本地 hdfs 到 gs
- wordpress - 我的网站产品档案页面仅显示我正在使用商务的两个产品,并且所有设置都正常,如何解决这个问题?
- python - ImportError:无法导入名称 Person