如果记录不存在则创建

时间:2014-02-12 04:01:48

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

我的rails应用程序中有3个模型

class Contact < ActiveRecord::Base
  belongs_to :survey, counter_cache: :contact_count
  belongs_to :voter
  has_many :contact_attempts
end

class Survey < ActiveRecord::Base
  has_many :questions
  has_many :contacts
end

class Voter < ActiveRecord::Base
  has_many :contacts
end

联系人包含voter_id和survey_id。我的应用程序的逻辑是,在任何给定的调查中,选民只能有一个联系人。

现在我正在使用以下代码来强制执行此逻辑。我在contacts表中查询与给定的voter_id和survey_id匹配的记录。如果不存在则创建它。否则它什么都不做。

if !Contact.exists?(:survey_id => survey, :voter_id => voter)
   c = Contact.new
   c.survey_id = survey
   c.voter_id = voter
   c.save
end

显然,这需要select和insert查询来创建1个潜在联系人。当我一次添加可能数千个联系人时。

现在我正在使用Resque来允许在后台运行并远离ui线程。我该怎么做才能加快速度,提高效率?

4 个答案:

答案 0 :(得分:27)

您可以执行以下操作:

Contact.where(survey_id: survey,voter_id: voter).first_or_create

答案 1 :(得分:17)

您应该首先添加一个数据库索引,以便将此条件强制设置为最低级别:

add_index :contacts, [:voter_id, :survey_id], unique: true

然后,您应该在ActiveRecord级别添加唯一性验证:

validates_uniqueness_of :voter_id, scope: [:survey_id]

如果指定选民和调查的联系人存在,则contact.save将返回false

更新:如果您创建索引,那么唯一性验证将非常快速地运行。

答案 2 :(得分:10)

查看这些链接是否可以为您提供帮助。

这些链接适用于rails 4.0.2,但您可以在api docks中进行更改

来自apidock:first_or_createfind_or_create_by
来自Rails指南:find-or-create-by

答案 3 :(得分:4)

如果让MySQL处理它会更好。

创建迁移并向<{1}}

添加复合唯一键
survey_id, voter_id

现在

add_index :contact, [:survey_id, :voter_id], :unique=> true

仅在没有重复项时才会创建新记录。