一對多關聯是最基礎的資料模型之一:訂單擁有多個明細項目、部門包含多名員工等。在 ActiveRecord 中,父模型使用 has_many,子模型使用 belongs_to 即可建立雙向導航。
class Order < ActiveRecord::Base has_many :line_items end class LineItem < ActiveRecord::Base belongs_to :order end
has_many 建立的關聯屬性表現如同陣列,支援 <<、push、each 等方法:
order = Order.new params[:products_to_buy].each do |prd_id, qty| product = Product.find(prd_id) order.line_items << LineItem.new(:product => product, :quantity => qty) end
<< 不僅將物件加入集合,還會自動設定子物件外鍵,並在父物件儲存時級連儲存子物件。
order = Order.find(123) total = 0.0 order.line_items.each do |li| total += li.quantity * li.unit_price end
:class_name、:foreign_key、:conditions、:order:與 has_one 相同:dependent:刪除父記錄時同步刪除子記錄(逐筆呼叫 destroy):exclusively_dependent:子表無其他關聯且無回呼時,單一 SQL 批次刪除,效能較佳:finder_sql、:counter_sql:完全自訂查詢與計數 SQL,適用於複雜條件class Order < ActiveRecord::Base
has_many :rails_line_items,
:class_name => "LineItem",
:finder_sql => "select l.* from line_items l, products p " +
"where l.product_id = p.id and p.title like '%rails%'"
end
:order 在 has_one 的妙用雖然 has_one 至多返回一筆,但搭配 :order 可實現「最新一筆」查詢:
class Customer < ActiveRecord::Base
has_many :orders
has_one :most_recent_order,
:class_name => 'Order',
:order => 'created_at DESC'
end
cust = Customer.find_by_name("Dave Thomas")
puts "Dave last ordered on #{cust.most_recent_order.created_at}"
ActiveRecord 產生 SQL:SELECT * FROM orders WHERE customer_id = ? ORDER BY created_at DESC LIMIT 1
has_many 新增的方法| 方法 | 說明 |
|---|---|
orders(force_reload=false) | 返回關聯陣列,結果快取;true 強制重讀 |
orders << order | 加入單一子物件並設定外鍵 |
orders.push(order1, ...) | 批次加入,concat 為別名 |
orders.delete(order1, ...) | 移除關聯(外鍵設 null),不刪除資料庫記錄 |
orders.clear | 清空關聯;若有 :dependent 則刪除記錄 |
orders.find(options...) | 限定於關聯範圍內查詢 |
orders.build(attrs) | 建構新物件並關聯,不儲存 |
orders.create(attrs) | 建構並儲存新物件 |