强制工厂内 2 字符字段唯一性的最佳方法?
Best way to force uniqueness of a 2-character field within a factory?
我有一个看起来像这样的乡村工厂
FactoryGirl.define do
factory :country do
name { "Country_Name_#{rand(10000).to_s}#{('a'..'z').to_a.shuffle.join.first(10)}" }
alpha { ('a'..'z').to_a.shuffle.join.first(2) }
end
end
alpha 是一个 2 个字母的国家代码,我验证了它的唯一性。
validates :alpha,
presence: true,
uniqueness:true,
length: {is: 2}
在运行宁大测试的时候,我经常运行进入
ActiveRecord::RecordInvalid:
Validation failed: Alpha has already been taken
特别是在创建子记录时
factory :state do
name { "State_Name_#{rand(10000).to_s}#{('a'..'z').to_a.shuffle.join.first(10)}" }
country
end
有没有更好的方法来构建我的国家工厂以避免重复?或者有没有更好的方法来构建国家工厂,以便 belongs_to 国家是新记录和现有记录的混合体
解决方案
对于其他遇到类似问题的人来说,序列绝对是正确的选择(感谢 born4new 和 Slicedpan)。
在实现这个过程中,我意识到我还有一些其他问题导致了问题。
首先,Database Cleaner 未正确 运行ning,因此数据库未在两次测试之间重置为干净状态。因此,我很快就 运行 重复了一遍。
我还发现我需要在每次测试后重置 FactoryGirl 序列。否则,对于长序列,我会看到 zx, zy, zz, a, b
,并且单个字符无法通过我的验证。
#spec/rails_helper.rb
config.append_after(:each) do
DatabaseCleaner.clean
FactoryGirl.reload
end
当事物必须独一无二时,我倾向于使用序列。对于国家代码,您需要枚举可能的国家代码。一种方式如下
sequence :country_code do |n|
i1 = n % 26
i2 = n / 26
chars = ('a'..'z').to_a
"#{chars[i1]}#{chars[i2]}"
end
然后在你的工厂里你可以简单地做
factory :country do
name { "Country_Name_#{rand(10000).to_s}#{('a'..'z').to_a.shuffle.join.first(10)}" }
alpha { generate :country_code }
end
When running large tests,
你最多(可能少一点)26^2 = 676
可能的 alpha 组合,所以如果 large tests
意味着更多,就没有办法解决它。
为了论证,我假设它小于那个。
您可以从 'AA' 和 'increment' 开始,像这样:
AB AC ... AZ BA BB BC ...etc
为此,您可以玩工厂女孩的序列(使用模数和除法):
sequence(:alpha) do |n|
('a'..'z').to_a[n / 26] + ('a'..'z').to_a[n % 26]
end
这比使用序列效率低(因为它需要读取数据库),但效果很好:
FactoryGirl.define do
factory :country do
alpha do
loop do
possible_state = ('a'..'z').to_a.sample(2).join
break possible_state unless Country.exists?(alpha: possible_state)
end
end
end
end
还要注意 sample
.
的使用
我有一个看起来像这样的乡村工厂
FactoryGirl.define do
factory :country do
name { "Country_Name_#{rand(10000).to_s}#{('a'..'z').to_a.shuffle.join.first(10)}" }
alpha { ('a'..'z').to_a.shuffle.join.first(2) }
end
end
alpha 是一个 2 个字母的国家代码,我验证了它的唯一性。
validates :alpha,
presence: true,
uniqueness:true,
length: {is: 2}
在运行宁大测试的时候,我经常运行进入
ActiveRecord::RecordInvalid:
Validation failed: Alpha has already been taken
特别是在创建子记录时
factory :state do
name { "State_Name_#{rand(10000).to_s}#{('a'..'z').to_a.shuffle.join.first(10)}" }
country
end
有没有更好的方法来构建我的国家工厂以避免重复?或者有没有更好的方法来构建国家工厂,以便 belongs_to 国家是新记录和现有记录的混合体
解决方案
对于其他遇到类似问题的人来说,序列绝对是正确的选择(感谢 born4new 和 Slicedpan)。
在实现这个过程中,我意识到我还有一些其他问题导致了问题。
首先,Database Cleaner 未正确 运行ning,因此数据库未在两次测试之间重置为干净状态。因此,我很快就 运行 重复了一遍。
我还发现我需要在每次测试后重置 FactoryGirl 序列。否则,对于长序列,我会看到 zx, zy, zz, a, b
,并且单个字符无法通过我的验证。
#spec/rails_helper.rb
config.append_after(:each) do
DatabaseCleaner.clean
FactoryGirl.reload
end
当事物必须独一无二时,我倾向于使用序列。对于国家代码,您需要枚举可能的国家代码。一种方式如下
sequence :country_code do |n|
i1 = n % 26
i2 = n / 26
chars = ('a'..'z').to_a
"#{chars[i1]}#{chars[i2]}"
end
然后在你的工厂里你可以简单地做
factory :country do
name { "Country_Name_#{rand(10000).to_s}#{('a'..'z').to_a.shuffle.join.first(10)}" }
alpha { generate :country_code }
end
When running large tests,
你最多(可能少一点)26^2 = 676
可能的 alpha 组合,所以如果 large tests
意味着更多,就没有办法解决它。
为了论证,我假设它小于那个。
您可以从 'AA' 和 'increment' 开始,像这样:
AB AC ... AZ BA BB BC ...etc
为此,您可以玩工厂女孩的序列(使用模数和除法):
sequence(:alpha) do |n|
('a'..'z').to_a[n / 26] + ('a'..'z').to_a[n % 26]
end
这比使用序列效率低(因为它需要读取数据库),但效果很好:
FactoryGirl.define do
factory :country do
alpha do
loop do
possible_state = ('a'..'z').to_a.sample(2).join
break possible_state unless Country.exists?(alpha: possible_state)
end
end
end
end
还要注意 sample
.