2016-09-19 91 views
2

我已经从Rails 3.2迁移到Rails 4。我有这样的:未定义方法`find_or_initialize'为关系

MyModel.find_or_initialize_by_field1("fdsfdsfds") 

现在我有这个

MyModel.where(field1: "fdsfdsfds").find_or_initialize 

现在导致在测试中的异常:

undefined method `find_or_initialize' for #<ActiveRecord::Relation []> 

但指南中也只字未提应该是还有什么那里。如何解决它?

+0

这是自动升级工具的结果吗? –

回答

2

发生这种情况是因为当返回的结果是一个空数组时,您无法调用它的find_or_initalize方法。尝试:

MyModel.where(field1: 'asdfasdfasdf').first_or_initialize 
1

MyModel.where(field1: "fdsfdsfds")回报的集合,其行为就像在许多方面的数组。如果你想打电话.find_or_initialize_by,传递一个哈希:

MyModel.find_or_initialize_by(field1: "fdsfdsfds") 

许多老.something_by_attr(x)方法可以一样干净地.something_by(attr: x)

0

表示虽然他们看起来很相似,你所提到的两个方法,find_or_initialize_by_Xfind_or_initialize,有很大的不同。

find_or_initialize_by_类型的方法是在ActiveRecord::Base的子类上定义的发现者,即主动记录模型。如果没有匹配查询条件,它们将返回单个记录或新实例。

第二个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") 

这是更接近find_or_initialize_by_X您在Rails的3.2使用,实际上一切您应该使用find_by而不是where(...).first模式,因为性能原因:where(...).first将导致SQL按主键排序,这将比find_by生成的SELECT慢。

相关问题