2015-10-13 35 views
2

我正在建設一個軌道網站,其中涉及一個定向的友誼關係。我知道在模型層面上,它是一個自我參照關聯。並且有關於該關聯的方法如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的指南

The Active Record way claims that intelligence belongs in your models, not in the database. As such, features such as triggers or constraints, which push some of that intelligence back into the database, are not heavily used.

我不知道是否在這種情況下,數據庫約束大量使用。

因此,在這種情況下,我真的需要設置數據庫級別約束(使用外鍵)嗎?或者我只需要認識模型層面的約束條件?謝謝!!

+0

你說它不起作用。什麼不行?在執行特定操作後是否收到特定的錯誤消息? –

+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 

要回答你的問題:我如何才能建立數據庫級別約束這種關係? 答:就像你已經有。

通常開發者會採用導軌方式並在模型中設置這些約束,但將它們設置在數據庫中是完全合理的。

編輯: 這將讓你創建一個表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 
+0

感謝您的回答。您解決了我是否有必要在數據庫中添加這樣一個約束的困惑。但是對於遷移代碼,友誼表中的兩個外鍵全都引用了用戶表。我沒有名爲Friend的表格。所以你的代碼不工作......我想我應該在這裏使用一些別名,但我找不到解決方案 –

+0

你不能有兩個同名的列。 SQL如何知道你在查詢中指的是哪個'user_id'?你不需要有一個「朋友」模型。這隻會創建一個「friend_id」關聯。您以後將其指定給軌道中的特定關聯模型。 – Magnuss

+0

但是在我的遷移文件中,如果我使用'belongs_to:friend',它會顯示錯誤'PG :: UndefinedTable:ERROR:relation「friends」does not exist'。 @Magnuss –

0

我想你弄不清的foreign_keys在你的數據庫架構中的作用。


ActiveRecord只是SQL的「塗層」。

它能夠形成查詢等,它允許你建立關聯的對象,因此你可以做的最重要的事情就是正確地關聯這些對象。

做到這一點的方式 - 在SQL - 是使用foreign_key,其實質上顯示的ActiveRecord的喜好(和SQL如果您使用join查詢)的數據關聯:

enter image description here

外鍵是關係數據庫結構的標準元素,您可能知道。


爲什麼數據結構失敗的原因是由於你複製你friendshipsuser_id外鍵的事實。

你要參考以下: 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能夠關聯同一模型的兩個對象的兩個外鍵。

+1

感謝您的回答!但似乎在數據庫級別,不能保證參照完整性,因爲遷移文件中的代碼不設置任何外鍵。我不確定我的理解是否正確? @ Rich Peck –

+0

它應該沒問題 –

+0

那麼,這是否意味着在這種情況下,在模型中設置約束就足夠了?在數據庫中設置約束是不必要的? @Rich Peck –