rails参考关联的数据库约束

时间:2015-10-13 08:00:54

标签: ruby-on-rails ruby database

我正在建立一个有关友情关系的铁路网站。我知道在模型层面,它是一个自我参照联想。对于该关联,有has_and_belongs_to等方法。

我的问题是:如何为此关系设置数据库级别约束。我想迁移将是这样的,它使用外键来保证参照完整性:

class CreateFriendships < ActiveRecord::Migration
  def change
    create_table :friendships do |t|
      t.belongs_to :user, null: false, foreign_key: true
      t.belongs_to :user, null: false, foreign_key: true

      t.integer :accepted, null: false, default: 0
    end
  end

但是当我运行rake db:migrate时,它有错误:

PG::DuplicateObject: ERROR:  constraint "fk_friendships_user_id" for relation "friendships" already exists

事实上,我甚至不确定在这种情况下我是否有必要设置数据库约束,因为我已经看到一些人实现了友谊关系没有像这样的数据库约束:

create_table :friendships do |t|
  t.integer :user_id
  t.integer :friend_id
  t.timestamps
end

根据Rails指南

  

Active Record方式声称智能属于您的模型,而不属于数据库。因此,诸如触发器或约束之类的功能(将某些智能推回到数据库中)并没有被大量使用。

我不确定在这种情况下是否大量使用数据库约束。

在这种情况下,我是否真的有必要设置数据库级别约束(使用外键)?或者我只需要在模型级别中实现约束?谢谢!

2 个答案:

答案 0 :(得分:1)

您已两次声明user关系:

  t.belongs_to :user, null: false, foreign_key: true
  t.belongs_to :user, null: false, foreign_key: true

似乎应该是这样的:

  t.belongs_to :user, null: false, foreign_key: true
  t.belongs_to :friend, null: false, foreign_key: true

回答您的问题:如何为此关系设置数据库级别约束? 答:就像你已经拥有的一样。

开发人员经常使用 rails方式并在模型中设置这些约束,但在数据库中设置它们是完全合理的。

编辑: 这样您就可以创建一个包含friend_id

的表格
class CreateFriendships < ActiveRecord::Migration
  def change
    create_table :friendships do |t|
      t.belongs_to :user, null: false, foreign_key: true
      t.integer :friend_id, null: false

      t.integer :accepted, null: false, default: 0
    end

    add_foreign_key :friendships, :users, column: :friend_id
  end
end

答案 1 :(得分:0)

我认为你对foreign_keys在数据库架构中的角色感到困惑。

ActiveRecord只是SQL的“涂层”。

它能够形成允许您构建关联对象的查询等,因此您可以做的最重要的事情是正确关联这些对象。

在SQL中执行此操作的方法是使用foreign_key,它基本上显示ActiveRecord(如果使用join查询则使用SQL),这些数据与哪些数据相关联:

enter image description here

外键是关系数据库结构的标准元素,您可能知道。

您的数据结构失败的原因是您在user_id表中复制了friendships外键。

您需要参考以下内容: Rails: self join scheme with has_and_belongs_to_many?

这表明如果你想创建一个自引用连接表(比如你正在做),你需要使用以下内容:

#app/models/user.rb
class User < ActiveRecord::Base
  has_and_belongs_to_many :friends, 
              class_name: "User", 
              join_table: :friendships, 
              foreign_key: :user_id, 
              association_foreign_key: :friend_user_id
end

#db/migrate/______.rb
class CreateFriendships < ActiveRecord::Migration
  def self.up
    create_table :friendships, id: false do |t|
      t.integer :user_id
      t.integer :friend_user_id
    end

    add_index(:friendships, [:user_id, :friend_user_id], :unique => true)
    add_index(:friendships, [:friend_user_id, :user_id], :unique => true)
  end

  def self.down
      remove_index(:friendships, [:friend_user_id, :user_id])
      remove_index(:friendships, [:user_id, :friend_user_id])
      drop_table :friendships
  end
end

请注意引用是针对user_idfriend_user_id的?

这是您需要确保has_and_belongs_to_many能够关联同一模型的两个对象所需的两个外键。

相关问题