鉴于用户可以拥有多个地址,我正在尝试验证给定用户只能拥有给定address_type
的一个地址。例如,用户可以拥有主地址和帐单地址,但用户不能拥有两个主地址。如何在我的模型上强制执行该规则,以及如何测试它?我目前最好的猜测是我需要验证address_type
的唯一性范围为user_id
,但此代码阻止两个地址存在相同类型。我见过其他人编写的代码与此非常相似,但检查字符串而不是枚举。
<!-- language: lang-ruby -->
# user.rb
class User < ApplicationRecord
has_many :addresses
end
# address.rb
class Address < ApplicationRecord
belongs_to :user
enum :address_type => { :primary, :mailing, :billing }
validates :address_type, :uniqueness => { :scope => :user_id }
end
答案 0 :(得分:1)
Rails唯一性验证与整数列完美匹配。但是,你的枚举定义不是有效的Ruby语法。
class Address < ApplicationRecord
belongs_to :user
enum :address_type => [ :primary, :mailing, :billing ]
# or preferably with Ruby 2.0+ hash syntax
enum address_type: [ :primary, :mailing, :billing ]
# ...
end
您可以通过调用模型实例上的.valid?
并检查errors object来测试验证:
require 'rails_helper'
RSpec.describe Address, type: :model do
let(:user) { create(:user) }
it "should require the user id to be unique" do
Address.create(user: user, address_type: :primary)
duplicate = Address.new(user: user, address_type: :primary)
expect(duplicate.valid?).to be_falsy
expect(duplicate.errors.full_messages_for(:address_type)).to include "Address type has already been taken"
end
end
谨防仅测试expect(duplicate.valid?).to be_falsy
和expect(duplicate.valid?)
因为它可能导致误报/否定。而是测试特定的错误消息或密钥。 Shoulda-matchers对于此目的非常好,但并非绝对必要。
require 'rails_helper'
RSpec.describe Address, type: :model do
# shoulda-matchers takes care of the boilerplate
it { should validate_uniqueness_of(:address_type).scoped_to(:user_id) }
end
您还应考虑在addresses.address_type
和addresses.user_id
上添加复合唯一索引,因为这会阻止race issues。