更新后,唯一性的自定义验证失败

时间:2016-10-11 15:04:47

标签: ruby-on-rails validation

我为模型full_name中的复合字段contact创建了自定义验证:

validate :full_name_must_be_unique

def full_name [last_name, first_name, mid_name].
       reject { |n| n.blank? }.join(' ') unless first_name.blank?
  nil
end

def full_name_must_be_unique
  contact = Contact.find_by(first_name: first_name, mid_name: mid_name, last_name: last_name)
  errors.add(:full_name, "must be unique") if contact.present?
end

验证适用于使用&#34更新时创建和失败; full_name必须是唯一的"信息。我想这是因为数据库中存在记录,如果我没有更改全名的属性,则验证失败。 如何解决问题? 控制器:

def update
  @contact = Contact.find(params[:id])
  if @contact.update(contact_params)
    redirect_to contacts_path, notice: "Contact updated."
  else
    render 'edit'
  end
end

更新 在@jonnynemonic和@MrYoshiji的帮助下,验证器的最终版本是:

def full_name_must_be_unique
  contact = Contact.where(["first_name = ? and mid_name = ? and last_name = ? and id <> ?", first_name, mid_name, last_name, id])
  errors.add(:full_name, "must be unique") if contact.present?
end

2 个答案:

答案 0 :(得分:0)

我的建议是对全名进行非规范化,然后只需添加validates_uniqueness_of:

迁移:

add_column :contacts, :full_name, :string

型号:

before_validation -> {
  self.full_name = [last_name, first_name, mid_name].
       reject { |n| n.blank? }.join(' ') unless first_name.blank?
}

validates_uniqueness_of :full_name

答案 1 :(得分:0)

您需要从查询结果中排除当前记录。确保在另一条记录中检测到双重性。

def full_name_must_be_unique
    contact = Contact.find_by(first_name: first_name, mid_name: mid_name, last_name: last_name)
    contact.each do |c| 
      if id != contact.id 
        errors.add(:full_name, "must be unique") if contact.present?
        return
      end
    end
end 

你也可以优化你的查询并获得第一个双重性,并确保它的双重性是另一个当前不同的记录。

您还可以在数据库中创建uniq索引作为预防