Rails-使用父级范围父级验证嵌套属性的唯一性 [英] Rails - Validate Nested Attributes Uniqueness with scope parent of parent

查看:105
本文介绍了Rails-使用父级范围父级验证嵌套属性的唯一性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Rails中对具有父项的父项的嵌套属性的范围唯一性验证存在问题.

I have a problem with the scoped uniqueness validation in Rails for nested attributes with a parent of parent.

背景

我有3种型号的Rails 4应用程序:

I have a rails 4 application with 3 models :

#app/models/account.rb
class Account < ActiveRecord::Base
  has_many :contacts, dependent: :destroy
end

#app/models/contact.rb
class Contact < ActiveRecord::Base
  belongs_to :account
  has_many :email_addresses, dependent: :destroy, validate: :true, inverse_of: :contact
  accepts_nested_attributes_for :email_addresses,allow_destroy: true
  validates :email_addresses, presence: true
end

#app/models/email_address.rb
class EmailAddress  < ActiveRecord::Base
  belongs_to :contact, inverse_of: :email_addresses

  validates :label, presence: true
  validates :contact, presence: true
  validates :email, uniqueness: true, presence: true
  validates_email_format_of :email
end

问题

我想确定一个范围,以确保属性:模型EmailAddress 的电子邮件在帐户级别上是唯一的(帐户是联系人"的父级,本身是EmailAddress的父级.)

I want make a scope, so as to make sure the attribute :email of the model EmailAddress is unique at the Account Level (Account is parent of Contact, which is itself parent of EmailAddress).

我在 http://guides.rubyonrails.org/active_record_validations.html 中建议,尝试过:

 class EmailAddress  < ActiveRecord::Base
  belongs_to :contact, inverse_of: :email_addresses

  validates :label, presence: true
  validates :contact, presence: true
  validates :email, presence: true, uniqueness: { scope: :account, 
                    message: "This contact email is already taken" }
  validates_email_format_of :email
 end

这将引发错误列email_addresses.account不存在" 我该怎么办 ?

This raises the error "column email_addresses.account does not exist" What should I do ?

感谢您的帮助!

推荐答案

下面将介绍一种在性能方面更好的选择.经过测试,效果很好.

A better option in terms of performances is described below. It is tested and works just fine.

为什么?

映射大量电子邮件时,映射电子邮件会消耗大量资源,因此最好直接在数据库中执行作用域.

Mapping emails can consume a lot of ressources when a lot of emails are at stake, so its better to perform the scope directly with the database.

如何?

在EmailAddress模型中兑现account_id并执行之前验证方法.

Cashing the account_id in the EmailAddress model and performing a before validation method.

1)创建迁移:

change_table :email_addresses do |t|
  t.references :account, index: true
end
add_index :email_addresses, [:account_id, :email], unique: true

2)迁移

3)更新EmailAddress模型

3) Update the EmailAddress model

#app/models/email_address.rb

class EmailAddress < ActiveRecord::Base
  belongs_to :contact, inverse_of: :email_addresses
  belongs_to :account

  validates :label, presence: true
  validates :contact, presence: true
  validates_email_format_of :email
  validates_uniqueness_of :email, allow_blank: false, scope: :account

  before_validation do
    self.account = contact.account if contact
  end

end

这篇关于Rails-使用父级范围父级验证嵌套属性的唯一性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆