2011-03-28 77 views
2

我想弄清楚一些關於軌道關係的東西。我已經發布了一個關於不久前的特定項目的問題,但我並不真正瞭解底層數據庫中做了什麼。軌道關係

我有一個Project模型和一個Client模型。 一個項目belongs_to :client =>我需要在項目表中手動添加client_id(使用遷移)。
A Clienthas_many :projects =>我不需要在數據庫中進行任何操作(無需遷移)。 project.clientclient.projects方法都可用。

我有一個Group模型和User模型。
一個Grouphas_and_belongs_to_many :user
一個Userhas_and_belongs_to_many :group 然後我需要創建一個遷移聯合打造的錶帶有user_idgroup_id指針。

我真的不知道rails和關係數據庫之間的邊界在哪裏。 爲什麼我需要添加外鍵有時但並非總是? has_many關係是如何處理的,因爲我沒有在這個特殊人物的底層數據庫中做任何事情?

我有點有時會丟失:)

感謝和問候,

呂克

回答

5

對於has_many < - >belongs_to assoication,你定義一個項目是獨資(belongs_to)由一個客戶。因此,該客戶有許多(has_many)項目。對於確定它屬於哪個客戶端的項目,它需要有一個client_id列,以便它可以查找它。這client_id列使用Rails在調用client方法,就像這樣:

Client.find(project.client_id) 

這就是你如何能找到一個項目的客戶端。 client_id列通常被稱爲外鍵,因爲它在表中不是其來源(「外來」)的唯一標識符(「鍵」)。繁榮。

當你周圍調用其他方法,找到所有的客戶端有項目,即client.projects,Rails會的這相當於:

Project.find_all_by_client_id(client.id) 

這則返回所有Project記錄它們與特定客戶端相關,基於projects表中的client_id字段。


隨着has_and_belongs_to_many協會,如用戶&組例子,你宣稱用戶has_and_belongs_to_many :groups。現在

,如果它是一個簡單的has_many :groups,外鍵會包含在groups表,或者如果它是一個belongs_to它會走在users表。好的事情要記住:外鍵總是在具有belongs_to的模型的表中。

您還聲明組has_and_belongs_to_many :users,所以我們遇到了同樣的問題。我們不能在用戶表中聲明密鑰,因爲它不屬於那裏(因爲用戶有很多組,您需要存儲用戶所屬的所有組ID)或組表,原因相同。

這就是爲什麼對於has_and_belongs_to_many我們需要創建所謂的連接表。這個表有兩個且只有兩個字段(它們都是外鍵),一個用於關聯的一側,另一個用於另一側。爲了創建這個表,我們會把這在遷移的self.up方法:

create_table :groups_users, :id => false do |t| 
    t.integer :group_id 
    t.integer :user_id 
end 

幾件事情要注意這裏:

  1. 表名是按字母順序排列的兩個協會的兩個名字。 G出現在U之前,所以表名是groups_users
  2. 這裏有:id選項,當給定值false生成一個沒有主鍵的表。連接表不需要主鍵,因爲其目的是將其他表連接在一起。
  3. 我們將group_iduser_id存儲爲整數字段,就像我們在belongs_to關聯中一樣。

該表格將跟蹤哪些組具有什麼用戶,反之亦然。

不需要在usersgroups表上定義附加列,因爲連接表已經得到了控制。

+0

非常感謝,這非常清楚。只是一件事,Client.find(project.client_id)與project.client是一樣的,對吧?什麼client.projects?此方法是否僅由has_many語句創建? – Luc 2011-03-29 08:12:30

+0

@Luc我已經更新了答案,就在休息時間之上。 – 2011-03-29 21:23:06

-1
class Customer < ActiveRecord::Base 
    has_many :orders, dependent: :destroy 
end 

class Order < ActiveRecord::Base 
    belongs_to :customer 
end 

@order = @customer.orders.create(order_date: Time.now)