Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails唯一性约束和空列的匹配db唯一索引_Ruby On Rails_Migration_Unique Index_Validates Uniqueness Of - Fatal编程技术网

Ruby on rails Rails唯一性约束和空列的匹配db唯一索引

Ruby on rails Rails唯一性约束和空列的匹配db唯一索引,ruby-on-rails,migration,unique-index,validates-uniqueness-of,Ruby On Rails,Migration,Unique Index,Validates Uniqueness Of,我的迁移文件中有以下内容 def self.up create_table :payment_agreements do |t| t.boolean :automatic, :default => true, :null => false t.string :payment_trigger_on_order t.references :supplier t.references :seller t.

我的迁移文件中有以下内容

  def self.up
    create_table :payment_agreements do |t|
      t.boolean    :automatic, :default => true, :null => false
      t.string     :payment_trigger_on_order
      t.references :supplier
      t.references :seller
      t.references :product
      t.timestamps
    end
  end
add_index :payment_agreements, :product_id, :unique => true
我希望确保如果指定了产品标识,那么它是唯一的,但我也希望允许null,因此我的模型中有以下内容:

  validates :product_id,
            :uniqueness => true,
            :allow_nil => true
很好,但是我应该在迁移文件中添加一个索引

  def self.up
    create_table :payment_agreements do |t|
      t.boolean    :automatic, :default => true, :null => false
      t.string     :payment_trigger_on_order
      t.references :supplier
      t.references :seller
      t.references :product
      t.timestamps
    end
  end
add_index :payment_agreements, :product_id, :unique => true
显然,当为product_id插入两个空值时,这会引发异常。我可以在迁移过程中省略索引,但有可能会得到两个具有相同product_id的PaymentAgreement,如下所示:


我的问题是,处理此问题的最佳/最常用方法是什么?一些主要的数据库系统不允许一个唯一索引包含多个null:unique既适用于null,也适用于非null。在数据库级别有很多方法可以解决这个问题(例如,触发器或计算列;请参阅)

您可以在应用程序级别解决这个问题,并进行验证,如果
产品\u id
不为空,则检查唯一性

validate :enforce_unique_product_id
def enforce_unique_product_id
  if (!self.product_id.nil? &&
      PaymentAgreement.exists?(:conditions=>['product_id = ?', self.product_id]))
    errors.add_to_base('There is already an agreement with product id " + 
                       self.product_id)
  end
end

(更新:正如zed_0xff所指出的,MySql允许在最常用的存储引擎中的唯一索引中使用多个null。)

这取决于您的db服务器。 至于mysql:

唯一索引创建约束 这样,索引中的所有值都必须 要清楚。如果您 尝试添加具有键值的新行 与现有行匹配的。这 约束不适用于NULL 除BDB存储之外的值 引擎。对于其他发动机,独特的 索引允许多个空值 可以包含NULL的列。


这个问题类似于验证:product_id,:if=>lambda{!self.product_id.nil?}的唯一性