在ActiveRecord中使用first_or_create的两种不同方式之间的差异

时间:2013-02-17 16:52:20

标签: ruby-on-rails ruby rails-activerecord

我是ActiveRecord的新手,所以这可能是一个愚蠢的问题: 我写了这样的方法:

sample_organizations = [ '37 Signals', 'Fog Creek'] 
sample_organizations.each { |item|
    Organization.first_or_create(
        name: item,
        time_zone: 'Central'
    )
  }

并且它没有工作,我希望它会遍历我的组织数组并将它们全部插入到数据库中,但它只插入了第一行。

然后有人建议改变它,这个就行了,但是我想知道是否有人可以解释第一种方法中的错误,这样我就可以了解我在做什么/假设错误。

所以这个有用了:

   sample_organizations = [ '37 Signals', 'Fog Creek'] 
    sample_organizations.each { |item|
    Organization.where(name: item).where(time_zone: 'Central').first_or_create
      }

2 个答案:

答案 0 :(得分:5)

实际上,有两种方法:find_or_create_by,添加一列并提供一组属性。

所以,例如你可以写:

find_or_create_by_name('Willy', time_zone: 'UTC')

第二个是first_or_create,这可以按照您的建议(您的第二个解决方案)运行(请参阅documentation)。

有人建议引入find_or_create方法,该方法接受哈希,但结果是first_or_create。 (见discussion)。

请注意,relevant rails guide中也都说明了这两点。

[更新2014-06-30]请注意,目前符号已更改,我们现在应该写

Organization.find_or_create_by(name: '37 signals') do |organisation|
  organisation.time_zone = 'Central'
end

将尝试按名称查找组织,如果未找到,则使用该块创建组织。注意:只有在组织不存在时才会执行该块!

答案 1 :(得分:4)

应该如下:

sample_organizations.each { |item|
  Organization.find_or_create_by_name(item, time_zone: 'Central')
}