关系的未定义方法`find_or_initialize'

时间:2016-09-19 15:52:58

标签: ruby-on-rails ruby ruby-on-rails-4 rspec

我已经从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 []>

但是在指南中它没有说明应该在那里做什么。如何解决?

3 个答案:

答案 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_Xfind_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慢。