Невозможно обновить запись из-за проверки имени

#ruby-on-rails

#ruby-on-rails

Вопрос:

 namespace :send_query do    
    task :to_admins => :environment do 
        contacts = Contact.select(:name, :mobile, :company, :requirement).where(email_sent: false).distinct
        if !contacts.blank?
            contacts.each do |contact|
                GuestMailer.query_email(contact.name,
          contact.mobile,
          contact.company,
          contact.requirement).deliver
          contact.update!(email_sent: true)
            end 
        end
        puts "done sending query emails"
    end
end
  

Я написал задачу rake для отправки электронных писем. После отправки электронной почты я обновляю поле email_sent на true. Но транзакция откатывается после отправки электронной почты.

 (0.2ms)  BEGIN
  Contact Exists (0.7ms)  SELECT  1 AS one FROM "contacts" WHERE "contacts"."name" = $1 AND ("contacts"."id" IS NOT NULL) AND "contacts"."mobile" = $2 AND "contacts"."requirement" = $3 AND "contacts"."company" = $4 LIMIT $5  [["name", "vamsi pavan mahesh"], ["mobile", "9247474925"], ["requirement", "yo yo honey singhu"], ["company", "mahesh@bla.com"], ["LIMIT", 1]]
   (0.2ms)  ROLLBACK
rake aborted!
ActiveRecord::RecordInvalid: Validation failed: Name has already been taken
  

Вот модель контакта

 # == Schema Information
#
# Table name: contacts
#
#  id          :integer          not null, primary key
#  name        :string
#  mobile      :string
#  company     :string
#  requirement :text
#  created_at  :datetime         not null
#  updated_at  :datetime         not null
#  email_sent  :boolean          default(FALSE)
#

class Contact < ApplicationRecord
    validates :name, presence: true 
    validates :mobile, presence: true
    validates :requirement, presence: true
    validates_uniqueness_of :name, scope: [:mobile, :requirement, :company]
end
  

Комментарии:

1. чтобы обойти проверку, вы можете сделать contact.update_attribute(:email_sent, true)

2. я хочу проверку! не могли бы вы перечитать вопрос

3. Это то, что мне не нравится в проверках: после того, как вы сохранили свою запись, и через некоторое время вы добавляете другую проверку, и эта старая запись не может пройти эту проверку, вы больше не сможете ее обновлять, даже если вы не измените атрибут, из-за которого проверка завершается неудачно. Обходной путь для его использования — использовать if условие проверки: validates :name, uniqueness: { scope: [:mobile, :requirement, :company] }, if: 'self.name_changed?'

4. @AndreyDeineko обход проверки следует выполнять только в очень редких случаях. Особенно не в задаче rake, которая предназначена для запуска время от времени

5. @MrYoshiji согласен, я не думаю, что обход проверки вообще приемлем (или, как вы говорите, очень редко). Иначе зачем это? 🙂

Ответ №1:

В вашей Contact модели вы можете сделать on: :create , и это будет применяться только для проверки действия create.

validates :name, presence: true, on: :create

Редактировать:

Как указал MrYoshiji в комментариях, именно uniqueness проверка имени вызывает ошибку проверки, поэтому исправление на самом деле будет:

validates :name, uniqueness: { scope: [:mobile, :requirement, :company] }, on: :create

Комментарии:

1. Я думаю, вы имели validates :name, uniqueness: { scope: [:mobile, :requirement, :company] }, on: :create в виду, что неудачная проверка связана с уникальностью имени, а не с наличием имени.

2. Ах, да, это правильно. Я обновлю свой ответ на то, что сказал MrYoshiji.

3. Я думаю, что это ненадежно. Если мы применим что-то к on: :create. Уже созданная запись может быть обновлена, чтобы иметь повторяющееся имя при ее обновлении