在 Rails 迁移中具有 has_many 的唯一性(不通过)
Uniqueness with has_many on Rails migration (without through)
我正在为省份和国家/地区创建 Rails 迁移。这个想法是,对于每个国家,我们不能允许多个省份同名。
我的 create_provinces 迁移是:
class CreateProvinces < ActiveRecord::Migration
def change
create_table :provinces do |t|
t.string :name
t.references :country, index: true, foreign_key: true
end
end
我的 country.rb 是:
class Country < ActiveRecord::Base
has_many :provinces, :uniq => true
end
我的province.rb是:
class Province < ActiveRecord::Base
belongs_to :country
private
validates_presence_of :country
validate :canada_or_usa?
validates_presence_of :name
validate :in_right_country?
validates_associated :country
def canada_or_usa?
errors.add(:country, "can only add province for Canada or the United States") unless (country.name == "Canada" || country.name == "United States")
end
def in_right_country?
if country.name == "Canada"
errors.add(:name, "Name must be the name of a province in Canada") unless (DataHelper::canada_provinces_with_caption.include? name)
end
if country.name == "United States"
errors.add(:name, "Name must be the name of a province in the United States") unless (DataHelper::usa_provinces_with_caption.include? name)
end
end
end
在 country.rb 中使用 :uniq => true
,我收到错误消息:uniq 不是已知密钥。请注意,根据其他问题,我也没有使用 through
。有没有办法确保每个国家不能有两个同名的省份?
在您的省模型中您需要添加
validates uniqueness: { scope: :country }
这将允许您拥有同名的省份,但不在一个国家内。
首先,:uniq => true
只会伪造数据的唯一性。当通过 some_country_instance.provinces
获取省份时,这会在查询中添加一个 DISTINCT 子句。有了它,您可以为一个国家插入两个同名的省份。我建议你删除它。你不想被骗。
您实际上应该做的是将 [country_id、province_name] 列添加为 table 个省份的主键。
您可以使用以下代码通过迁移完成此操作:
...
def change
add_index :provinces, [:country_id, :name], unique: true
end
...
我假设您的 table provinces
将 country_id
作为 countries
的外键列,并且 name
列包含省份名称。
为了验证模型中的数据,我建议:
...
validates :name, uniqueness: { scope: :country_id,
message: "My world my rules. Country cannot have provinces with same name." }
...
有了它,您将用几行代码优雅地完成您的工作,并充分利用 Rails 框架。
正确的语法是
has_many :provinces, -> { uniq }
然而,这只是定义了一个关联,并没有真正验证数据库的输入。如果你看 sql 你会看到类似的东西。
Select distinct provinces from provinces where provinces.country_id = '';
我正在为省份和国家/地区创建 Rails 迁移。这个想法是,对于每个国家,我们不能允许多个省份同名。
我的 create_provinces 迁移是:
class CreateProvinces < ActiveRecord::Migration
def change
create_table :provinces do |t|
t.string :name
t.references :country, index: true, foreign_key: true
end
end
我的 country.rb 是:
class Country < ActiveRecord::Base
has_many :provinces, :uniq => true
end
我的province.rb是:
class Province < ActiveRecord::Base
belongs_to :country
private
validates_presence_of :country
validate :canada_or_usa?
validates_presence_of :name
validate :in_right_country?
validates_associated :country
def canada_or_usa?
errors.add(:country, "can only add province for Canada or the United States") unless (country.name == "Canada" || country.name == "United States")
end
def in_right_country?
if country.name == "Canada"
errors.add(:name, "Name must be the name of a province in Canada") unless (DataHelper::canada_provinces_with_caption.include? name)
end
if country.name == "United States"
errors.add(:name, "Name must be the name of a province in the United States") unless (DataHelper::usa_provinces_with_caption.include? name)
end
end
end
在 country.rb 中使用 :uniq => true
,我收到错误消息:uniq 不是已知密钥。请注意,根据其他问题,我也没有使用 through
。有没有办法确保每个国家不能有两个同名的省份?
在您的省模型中您需要添加
validates uniqueness: { scope: :country }
这将允许您拥有同名的省份,但不在一个国家内。
首先,:uniq => true
只会伪造数据的唯一性。当通过 some_country_instance.provinces
获取省份时,这会在查询中添加一个 DISTINCT 子句。有了它,您可以为一个国家插入两个同名的省份。我建议你删除它。你不想被骗。
您实际上应该做的是将 [country_id、province_name] 列添加为 table 个省份的主键。
您可以使用以下代码通过迁移完成此操作:
...
def change
add_index :provinces, [:country_id, :name], unique: true
end
...
我假设您的 table provinces
将 country_id
作为 countries
的外键列,并且 name
列包含省份名称。
为了验证模型中的数据,我建议:
...
validates :name, uniqueness: { scope: :country_id,
message: "My world my rules. Country cannot have provinces with same name." }
...
有了它,您将用几行代码优雅地完成您的工作,并充分利用 Rails 框架。
正确的语法是
has_many :provinces, -> { uniq }
然而,这只是定义了一个关联,并没有真正验证数据库的输入。如果你看 sql 你会看到类似的东西。
Select distinct provinces from provinces where provinces.country_id = '';