我已经从Rails 3.2迁移到Rails 4。我有这个:
MyModel.find_or_initialize_by_field1("fdsfdsfds")
现在我有了这个
MyModel.where(field1: "fdsfdsfds").find_or_initialize
现在导致测试中出现异常:
undefined method `find_or_initialize' for #<ActiveRecord::Relation []>
但是在指南中它没有说明应该在那里做什么。如何解决?
答案 0 :(得分:1)
这种情况正在发生,因为当返回的结果为空数组时,您无法在其上调用find_or_initalize方法。尝试:
MyModel.where(field1: 'asdfasdfasdf').first_or_initialize
答案 1 :(得分:1)
MyModel.where(field1: "fdsfdsfds")
返回一个在许多方面表现得像数组的集合。如果您想调用.find_or_initialize_by
,请传入哈希:
MyModel.find_or_initialize_by(field1: "fdsfdsfds")
许多旧.something_by_attr(x)
方法可以与.something_by(attr: x)
答案 2 :(得分:0)
虽然它们看起来很相似,但您提到的两种方法find_or_initialize_by_X
和find_or_initialize
却截然不同。
find_or_initialize_by_
- 类型方法是在ActiveRecord::Base
的子类上定义的查找程序,即activerecord模型。它们返回单个记录,如果没有匹配查询条件,则返回新实例。
第二个find_or_initialze
方法不是在模型类(MyModel
)上调用,而是(如错误所示)在ActiveRecord::Relation
上调用。那是因为当你调用where
时,得到的结果是关系,而不是数组或单个记录。
虽然数组和关系看起来很相似,但Rails会避免将关系转换为数组,直到它没有其他选择,因为这样做意味着实际执行SQL并创建对象,这样做性能很重,只有在需要实际检查时才需要结果。
第二次调用find_or_initialize
时遇到的问题是ActiveRecord::Relation
没有find_or_initialize
方法;它有一个first_or_initialize
方法。 (它与上述情况下结果集为空的事实无关。)first_or_initialize
获取关系中的第一个结果,或者如果结果为空则初始化新模型。
所以简短的回答是你应该致电:MyModel.where(field1: 'foo').first_or_initialize
。
正如其他答案中所提到的,如果不使用关系,还有其他方法可以做同样的事情,例如:
MyMode.find_or_initialize_by(field1: "foo")
这更接近您在Rails 3.2中使用的find_or_initialize_by_X
,实际上在其他条件相同的情况下,出于性能原因,您应该使用find_by
而不是where(...).first
模式:{{1}将导致按主键排序的SQL,这将比where(...).first
生成的SELECT
慢。