Создать, если запись не существует
У меня есть 3 модели в моем приложении rails
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. Логика моего приложения заключается в том, что в любом опросе может быть только один контакт для избирателя.
прямо сейчас я использую следующий код для обеспечения соблюдения этой логики. Я запрашиваю таблицу контактов для записей, соответствующих данным 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
Очевидно, для этого требуется запрос выбора и вставки для создания 1 потенциального контакта. Когда я добавляю потенциально тысячи контактов сразу.
Сейчас я использую Resque, чтобы разрешить этот прогон в фоновом режиме и подальше от нити ui. Что я могу сделать, чтобы ускорить это и сделать его более эффективным?
Ответы
Ответ 1
Вы должны сначала добавить индекс базы данных, чтобы принудительно выполнить это условие на самом нижнем уровне:
add_index :contacts, [:voter_id, :survey_id], unique: true
Затем вы должны добавить проверку уникальности на уровне ActiveRecord:
validates_uniqueness_of :voter_id, scope: [:survey_id]
Затем contact.save
вернет false
, если контакт существует для указанного избирателя и опроса.
UPDATE: если вы создадите индекс, то проверка уникальности будет выполняться довольно быстро.
Ответ 2
Вы можете сделать следующее:
Contact.where(survey_id: опрос, voter_id: избиратель).first_or_create
Ответ 3
Посмотрите, могут ли эти ссылки помочь вам.
Эти ссылки предназначены для рельсов 4.0.2, но вы можете изменить их в api docks
Из apidock: first_or_create, find_or_create_by
Из руководства Rails: find-or-create-by
Ответ 4
Было бы лучше, если бы вы позволили MySQL справиться с этим.
Создайте перенос и добавьте составной уникальный ключ в survey_id, voter_id
add_index :contact, [:survey_id, :voter_id], :unique=> true
Теперь
Contact.create(:survey_id=>survey, :voter_id=>voter_id)
Создает новую запись только в том случае, если дубликатов нет.