on_many on Rails迁移的唯一性(不通过)

时间:2016-07-20 18:25:21

标签: ruby-on-rails ruby-on-rails-3

我正在为省份和国家/地区创建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

我的省份.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。有没有办法确保每个国家都有两个同名的省份?

3 个答案:

答案 0 :(得分:0)

在您的省份模型中,您需要添加

validates uniqueness: { scope: :country }

这将允许您拥有相同名称但不在一个国家/地区内的省份。

答案 1 :(得分:0)

首先,:uniq => true除了伪造数据的唯一性外什么都不做。当按some_country_instance.provinces获取省份时,会在查询中添加DISTINCT子句。有了它,您可以为一个国家/地区插入两个具有相同名称的省份。我建议你删除它。你不会被欺骗。

您实际应该做的是将对[country_id,province_name]列添加为表省的主键。

您可以使用以下代码进行迁移:

...
def change
   add_index :provinces, [:country_id, :name], unique: true
end
...

我假设您的表格provincescountry_id作为countries的外键列,name列保留省份&#39}名。

要验证模型中的数据,我建议:

...
validates :name, uniqueness: { scope: :country_id,
           message: "My world my rules. Country cannot have provinces with same name." }
...

通过这种方式,您只需几行代码并充分利用Rails框架即可优雅地完成工作。

答案 2 :(得分:0)

正确的语法是

has_many :provinces, -> { uniq }

然而,这只是定义关联而不是实际验证数据库的输入。如果你看看sql,你会看到类似的东西。

Select distinct provinces from provinces where provinces.country_id = '';