2

我希望能够build通过其 STI 类型在以特定模型类为目标的范围上调用该方法,并让 ActiveRecord 构建正确类的实例。

class LineItem < ActiveRecord::Base
  scope :discount, where(type: 'DiscountLineItem')
end

class DiscountLineItem < LineItem; end

> LineItem.discount.build # Expect an instance of DiscountLineItem here
=> #<LineItem ...>

在这里,我期望的是 的实例DiscountLineItem,而不是 的实例LineItem

4

2 回答 2

4

尽管 ActiveRecord 没有将对象实例化为正确的类,但它确实正确设置了类型。您基本上有两种解决方法:

1)创建对象,然后从数据库中重新加载它:

item = LineItem.discount.create(attrs...)
item = LineItem.find(item.id)

2) 使用 STI 类并直接从中构建对象:

DiscountLineItem.build

有了 ActiveRecord 可以做的所有事情,这似乎是一种毫无意义的限制,并且可能不会太难改变。现在你激起了我的兴趣:)

更新:

这是最近添加到 Rails 4.0的,带有以下提交消息:

允许您执行 BaseClass.new(:type => "SubClass") 以及 parent.children.build(:type => "SubClass") 或 parent.build_child 来初始化 STI 子类。确保类名是一个有效的类,并且它在关联所期望的超类的祖先中。

于 2012-07-09T00:43:51.623 回答
1

暂时忘掉吧build。如果你有一些LineItem l,你l.discount会得到LineItem实例,而不是DiscountLineItem实例。如果你想获取DiscountLineItem实例,我建议将范围转换为方法

def self.discount
  where(type: 'DiscountLineItem').map { |l| l.becomes(l.type.constantize) }
end

现在您将获得一组DiscountLineItem实例。

于 2012-07-09T00:44:10.743 回答