Ruby-on-rails 如果记录不存在则创建

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21718351/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 23:21:21  来源:igfitidea点击:

Create if record does not exist

ruby-on-railsruby-on-rails-4

提问by gsueagle2008

I have 3 models in my rails app

我的 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

the Contact consists of the voter_id and a survey_id. The Logic of my app is that a there can only be one contact for a voter in any given survey.

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

right now I am using the following code to enforce this logic. I query the contacts table for records matching the given voter_id and survey_id. if does not exist then it is created. otherwise it does nothing.

现在我正在使用以下代码来强制执行此逻辑。我在联系人表中查询与给定的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

Obviously this requires a select and a insert query to create 1 potential contact. When I am adding potentially thousands of contacts at once.

显然,这需要一个选择和一个插入查询来创建 1 个潜在的联系人。当我一次添加潜在的数千个联系人时。

Right now I'm using Resque to allow this run in the background and away from the ui thread. What can I do to speed this up, and make it more efficient?

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

采纳答案by Nicolas Garnil

You should add first a database index to force this condition at the lowest level as possible:

您应该首先添加一个数据库索引以在尽可能低的级别强制此条件:

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

Then you should add an uniqueness validation at an ActiveRecord level:

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

validates_uniqueness_of :voter_id, scope: [:survey_id]

Then contact.savewill return falseif a contact exists for a specified voter and survey.

然后contact.save将返回false如果联系人存在指定的投票和调查。

UPDATE: If you create the index, then the uniqueness validation will run pretty fast.

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

回答by bazinga012

You can do the following:

您可以执行以下操作:

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

回答by cassioscabral

See if those links can help you.

看看这些链接是否可以帮助您。

Those links are for rails 4.0.2, but you can change in the api docks

这些链接适用于 rails 4.0.2,但您可以在 api 码头中更改

From the apidock: first_or_create, find_or_create_by
From the Rails Guide: find-or-create-by

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

回答by Siva

It would be better if you let MySQL to handle it.

如果你让 MySQL 来处理它会更好。

Create a migration and add a composite unique keyto survey_id, voter_id

创建迁移并将复合唯一键添加到survey_id, voter_id

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

Now

现在

Contact.create(:survey_id=>survey, :voter_id=>voter_id) 

Will create new record only if there is no duplicates.

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