The Types of Associations
在 Rails 中,可以透過 ActiveRecord 來定義不同型別的關聯關係(Associations),包括以下幾種:
-
belongs_to:表示該模型
belongs_to
另一個模型,即該模型擁有一個外來鍵(foreign key)指向另一個模型的主鍵(primary key),通常用於表示一對一或多對一的關係。 -
has_one:表示該模型
has_one
另一個模型,即另一個模型擁有一個外來鍵指向該模型的主鍵,通常用於表示一對一的關係。 -
has_many:表示該模型
has_many
另一個模型,即另一個模型擁有一個外來鍵指向該模型的主鍵,通常用於表示一對多的關係。 -
has_many :through:表示透過中間模型建立多對多的關係,通常用於表示多對多的關係。
-
has_one :through:表示透過中間模型建立一對一或多對一的關係。
-
has_and_belongs_to_many:表示建立一個簡單的多對多的關係,通常用於表示只有兩個模型之間的多對多關係。
需要注意的是,這些關聯關係需要在模型之間正確定義和設定,才能夠正確地在應用程式中使用,並且需要考慮到關聯關係的型別、方向、外來鍵、中間模型等因素。正確地定義和使用關聯關係,可以方便地查詢和操作相關資料,並且可以避免出現不必要的程式碼和邏輯。
belongs_to
class CreateBooks < ActiveRecord::Migration[7.0]
def change
create_table :authors do |t|
t.string :name
t.timestamps
end
create_table :books do |t|
t.belongs_to :author
t.datetime :published_at
t.timestamps
end
end
end
這是一個建立 authors
和 books
兩個資料庫表的遷移檔案。authors
表包含一個 name
欄位和 created_at
和 updated_at
兩個時間戳欄位,books
表包含一個 author_id
外來鍵欄位來關聯 authors
表,一個 published_at
欄位和 created_at
和 updated_at
兩個時間戳欄位。
在 Rails 中,遷移檔案用於建立、修改和刪除資料庫表和欄位。這個遷移檔案中的 change
方法定義瞭如何建立 authors
和 books
兩個表。在 create_table
塊中,我們可以宣告表中的欄位和型別,以及其他選項,如外來鍵關聯等。在這個例子中,我們使用 belongs_to
方法來宣告 books
表與 authors
表之間的關聯關係。
當我們執行這個遷移檔案時,Rails 將會執行 change
方法中的程式碼,並在資料庫中建立 authors
和 books
兩個表。同時,Rails 還會自動建立 author_id
外來鍵索引,以確保 books
表中的每個行都關聯到 authors
表中的一個行。
belongs_to
不能確保引用一致性,因此根據用例,您可能還需要在引用列上新增資料庫級外來鍵約束,如下所示:
create_table :books do |t|
t.belongs_to :author, foreign_key: true
# ...
end
has_one
當使用 has_one
方法時,一個模型將擁有另一個模型的一個例項作為其屬性之一。這通常用於表示一對一關係,其中一個模型記錄與另一個模型的關聯,而另一個模型只有一個與之相關的記錄。
以下是一個使用 has_one
方法的例子,假設有一個 User
模型和一個 Profile
模型,每個使用者只有一個個人資料:
class User < ApplicationRecord
has_one :profile
end
class Profile < ApplicationRecord
belongs_to :user
end
在上面的程式碼中,User
模型使用 has_one
方法宣告瞭與 Profile
模型之間的關聯關係,而 Profile
模型使用 belongs_to
方法宣告瞭與 User
模型之間的關聯關係。
在這個例子中,User
模型將獲得一個名為 profile
的屬性,可以使用它來訪問與使用者相關聯的個人資料。例如,可以使用 user.profile
來獲取使用者的個人資料。在 Profile
模型中,user
屬性將被用於訪問與個人資料相關聯的使用者。
值得注意的是,在 has_one
方法中,預設情況下,Rails 將使用 user_id
欄位作為外來鍵來關聯兩個模型,因此在 Profile
模型中需要使用 belongs_to
方法來宣告與 User
模型之間的關聯關係。
has_one :through
has_one :through
是 Rails 中用於宣告一對一關係的方法,它用於表示兩個模型之間透過第三個關聯模型建立的關係。這個方法通常用於表示一個模型與另一個模型之間的一對一關係,其中一個模型可以關聯一個與之關聯的記錄,而每個關聯記錄只能關聯一個與之關聯的記錄。
以下是一個使用 has_one :through
方法的例子,假設有一個 User
模型和一個 Profile
模型,它們之間透過 ProfileLink
模型建立關聯,每個使用者只能擁有一個個人資料:
class User < ApplicationRecord
has_one :profile_link
has_one :profile, through: :profile_link
end
class Profile < ApplicationRecord
has_one :profile_link
has_one :user, through: :profile_link
end
class ProfileLink < ApplicationRecord
belongs_to :user
belongs_to :profile
end
在上面的程式碼中,User
模型和 Profile
模型都使用 has_one :through
方法宣告瞭與 ProfileLink
模型之間的關聯關係,而 ProfileLink
模型使用 belongs_to
方法宣告瞭與 User
模型和 Profile
模型之間的關聯關係。
在這個例子中,User
模型將獲得一個名為 profile
的屬性,可以使用它來訪問與使用者相關聯的個人資料。例如,可以使用 user.profile
來獲取與使用者相關聯的個人資料。在 Profile
模型中,user
屬性將被用於訪問與個人資料相關聯的使用者。
值得注意的是,在 has_one :through
方法中,需要指定透過哪個關聯模型建立一對一關係,例如:has_one :profile, through: :profile_link
表示 User
模型透過 ProfileLink
模型與 Profile
模型建立了一對一關係。
同時,在這個例子中,ProfileLink
模型還可以新增其他屬性,例如 status
表示使用者的個人資料狀態等,以便更好地描述關聯關係。
has_many
has_many
是 Rails 中用於宣告一對多關係的方法,它用於表示一個模型物件擁有多個其他模型物件的集合。這個方法通常用於表示一個模型與另一個模型之間的關聯,其中一個模型可以擁有多個與之關聯的記錄。
以下是一個使用 has_many
方法的例子,假設有一個 User
模型和一個 Post
模型,每個使用者可以擁有多篇文章:
class User < ApplicationRecord
has_many :posts
end
class Post < ApplicationRecord
belongs_to :user
end
在上面的程式碼中,User
模型使用 has_many
方法宣告瞭與 Post
模型之間的關聯關係,而 Post
模型使用 belongs_to
方法宣告瞭與 User
模型之間的關聯關係。
在這個例子中,User
模型將獲得一個名為 posts
的屬性,可以使用它來訪問與使用者相關聯的所有文章。例如,可以使用 user.posts
來獲取與使用者相關聯的所有文章。在 Post
模型中,user
屬性將被用於訪問與文章相關聯的使用者。
值得注意的是,在 has_many
方法中,預設情況下,Rails 將使用 user_id
欄位作為外來鍵來關聯兩個模型,因此在 Post
模型中需要使用 belongs_to
方法來宣告與 User
模型之間的關聯關係。
has_many :through
has_many :through
是 Rails 中用於宣告多對多關係的方法,它用於表示兩個模型之間透過第三個關聯模型建立的關係。這個方法通常用於表示一個模型與另一個模型之間的多對多關係,其中一個模型可以關聯多個與之關聯的記錄,而每個關聯記錄都可以關聯多個與之關聯的記錄。
以下是一個使用 has_many :through
方法的例子,假設有一個 User
模型和一個 Group
模型,它們之間透過 Membership
模型建立關聯,每個使用者可以屬於多個組:
class User < ApplicationRecord
has_many :memberships
has_many :groups, through: :memberships
end
class Group < ApplicationRecord
has_many :memberships
has_many :users, through: :memberships
end
class Membership < ApplicationRecord
belongs_to :user
belongs_to :group
end
在上面的程式碼中,User
模型和 Group
模型都使用 has_many :through
方法宣告瞭與 Membership
模型之間的關聯關係,而 Membership
模型使用 belongs_to
方法宣告瞭與 User
模型和 Group
模型之間的關聯關係。
在這個例子中,User
模型將獲得一個名為 groups
的屬性,可以使用它來訪問與使用者相關聯的所有組。例如,可以使用 user.groups
來獲取與使用者相關聯的所有組。在 Group
模型中,users
屬性將被用於訪問所有屬於該組的使用者。
值得注意的是,在 has_many :through
方法中,需要指定透過哪個關聯模型建立多對多關係,例如:has_many :groups, through: :memberships
表示 User
模型透過 Membership
模型與 Group
模型建立了多對多關係。
同時,在這個例子中,Membership
模型還可以新增其他屬性,例如 status
表示使用者在組中的狀態等,以便更好地描述關聯關係。
has_many
和 has_many :through
都是 Rails 中用於建立關聯關係的方法,但它們之間有一些區別。
has_many :through和has_many 區別
has_many
建立的是一對多的關聯關係,其中一個模型物件擁有多個其他模型物件的集合。這個方法通常用於表示一個模型與另一個模型之間的關聯,其中一個模型可以擁有多個與之關聯的記錄。例如,一個使用者可以擁有多篇文章。
has_many :through
建立的是多對多的關聯關係,其中兩個模型之間透過第三個關聯模型建立的關係。這個方法通常用於表示一個模型與另一個模型之間的多對多關係,其中一個模型可以關聯多個與之關聯的記錄,而每個關聯記錄都可以關聯多個與之關聯的記錄。例如,一個使用者可以屬於多個組,一個組也可以有多個使用者。
因此,has_many :through
更加靈活,可以用於建立更為複雜的關聯關係。同時,has_many :through
還可以在關聯模型中新增其他屬性,例如關聯記錄的狀態等。
需要注意的是,在使用 has_many :through
方法建立多對多關聯關係時,需要指定透過哪個關聯模型建立多對多關係。而在使用 has_many
建立一對多關聯關係時,則不需要指定。
The has_and_belongs_to_many Association
has_and_belongs_to_many
是 Rails 中用於宣告多對多關係的另一種方法,與 has_many :through
不同的是,它不需要使用第三個關聯模型來建立多對多關係。這個方法通常用於表示兩個模型之間的多對多關係,其中一個模型可以關聯多個與之關聯的記錄,而每個關聯記錄也可以關聯多個與之關聯的記錄。
以下是一個使用 has_and_belongs_to_many
方法的例子,假設有一個 Book
模型和一個 Author
模型,它們之間建立了多對多關係:
class Book < ApplicationRecord
has_and_belongs_to_many :authors
end
class Author < ApplicationRecord
has_and_belongs_to_many :books
end
在上面的程式碼中,Book
模型和 Author
模型都使用 has_and_belongs_to_many
方法宣告瞭彼此之間的多對多關係。
在這個例子中,Book
模型將獲得一個名為 authors
的屬性,可以使用它來訪問與圖書相關聯的所有作者。例如,可以使用 book.authors
來獲取與書籍相關聯的作者列表。在 Author
模型中,books
屬性將被用於訪問與作者相關聯的所有書籍。
需要注意的是,在使用 has_and_belongs_to_many
方法建立多對多關聯關係時,需要在資料庫中建立一箇中間表來儲存關聯關係。這個中間表的名稱應該是兩個模型名稱的複數形式的字母排序後的連線,例如,在上面的例子中,中間表的名稱應該是 authors_books
。
同時,使用 has_and_belongs_to_many
方法建立多對多關聯關係時,不能在中間表中新增其他屬性,因為它只是用於儲存兩個模型之間的關聯關係。如果需要在關聯關係中新增其他屬性,應該使用 has_many :through
方法來建立多對多關係。
Choosing Between belongs_to and has_one
在 Rails 中,belongs_to
和 has_one
是兩種用於定義兩個模型之間的一對一關係的方法。選擇它們之間的方法取決於兩個模型之間關係的性質。
當外來鍵儲存在宣告關聯的模型的表中時,使用 belongs_to
。例如,考慮一個 Car
模型,它屬於一個 Manufacturer
:
class Car < ApplicationRecord
belongs_to :manufacturer
end
class Manufacturer < ApplicationRecord
has_many :cars
end
在這個例子中,cars
表有一個外來鍵 manufacturer_id
引用 manufacturers
表。由於外來鍵儲存在 cars
表中,我們在 Car
模型中使用 belongs_to
來定義關聯。
另一方面,當外來鍵儲存在關聯模型的表中時,使用 has_one
。例如,考慮一個 Person
模型,它有一個 Address
:
class Person < ApplicationRecord
has_one :address
end
class Address < ApplicationRecord
belongs_to :person
end
在這個例子中,addresses
表有一個外來鍵 person_id
引用 people
表。由於外來鍵儲存在 addresses
表中,我們在 Person
模型中使用 has_one
來定義關聯。
一般來說,選擇 belongs_to
還是 has_one
取決於外來鍵儲存的位置。如果它儲存在宣告關聯的模型的表中,使用 belongs_to
。如果它儲存在關聯模型的表中,使用 has_one
。
Choosing Between has_many :through and has_and_belongs_to_many
在 Rails 中,has_many :through
和 has_and_belongs_to_many
是兩種用於定義多對多關係的方法。選擇它們之間的方法取決於你是否需要在關聯關係中儲存其他屬性。
has_many :through
允許你使用中間模型來連線兩個模型,並且可以在中間模型中儲存其他屬性。這使得 has_many :through
更加靈活,適用於需要在關聯關係中儲存更多資訊的情況。例如,考慮一個 Patient
模型和一個 Doctor
模型,它們之間需要建立多對多關係,而每個關聯關係還需要儲存一個 appointment_date
屬性:
class Patient < ApplicationRecord
has_many :appointments
has_many :doctors, through: :appointments
end
class Doctor < ApplicationRecord
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ApplicationRecord
belongs_to :patient
belongs_to :doctor
end
在上面的例子中,Patient
模型和 Doctor
模型之間的多對多關係透過 Appointment
模型建立。Appointment
模型中儲存了 appointment_date
屬性,表示預約時間。可以使用以下程式碼來訪問與患者相關聯的所有醫生:
patient.doctors
has_and_belongs_to_many
允許你在兩個模型之間建立簡單的多對多關係,但不能在中間表中儲存其他屬性。因此,如果你不需要在關聯關係中儲存其他屬性,可以使用 has_and_belongs_to_many
。例如,考慮一個 Student
模型和一個 Course
模型,它們之間需要建立多對多關係:
class Student < ApplicationRecord
has_and_belongs_to_many :courses
end
class Course < ApplicationRecord
has_and_belongs_to_many :students
end
在上面的例子中,Student
模型和 Course
模型之間的多對多關係可以直接透過中間表建立,而不需要使用中間模型。
總之,如果你需要在關聯關係中儲存其他屬性,應該使用 has_many :through
。如果不需要儲存其他屬性,則可以使用 has_and_belongs_to_many
來建立多對多關係。
Polymorphic Associations
在 Rails 中,多型關聯(Polymorphic Associations)允許一個模型屬於多個不同型別的其他模型,同時這些其他模型也可以有多個關聯的模型。這種關聯通常用於需要共享相同行為或屬性的模型之間。
例如,考慮一個 Comment
模型,它可以屬於多個其他模型(例如 Post
和 Photo
),同時這些其他模型也可以有多個評論:
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
class Post < ApplicationRecord
has_many :comments, as: :commentable
end
class Photo < ApplicationRecord
has_many :comments, as: :commentable
end
在上面的例子中,Comment
模型使用 belongs_to
方法宣告瞭多型關聯。commentable
是一個多型關聯欄位,它可以屬於任何其他模型。在 Post
和 Photo
模型中,使用 has_many
方法宣告瞭多型關聯關係,並使用 as
選項指定了多型關聯欄位的名稱。
使用多型關聯時,需要在資料庫中建立一個 comments
表。這個表需要包含一個 commentable_type
欄位和一個 commentable_id
欄位,用於儲存關聯的模型。可以使用以下程式碼建立 comments
表:
rails generate migration CreateComments commentable:references{polymorphic}:index body:text
上面的程式碼將生成一個名為 CreateComments
的遷移檔案,該檔案將建立一個 comments
表,並新增一個 commentable_type
欄位和一個 commentable_id
欄位,同時還新增了一個 body
欄位用於儲存評論內容。
可以使用以下程式碼來訪問與 Post
相關聯的所有評論:
post.comments
可以使用以下程式碼來訪問與 Photo
相關聯的所有評論:
photo.comments
總之,多型關聯允許一個模型屬於多個不同型別的其他模型,並且這些其他模型也可以有多個關聯的模型。這種關聯通常用於需要共享相同行為或屬性的模型之間。
Self Joins
Self Joins 是指在一個表中,透過外來鍵關聯自身的另一行資料。Self Joins 常用於需要建立層次結構的資料模型,例如組織結構、分類等。
在 Rails 中,可以透過在模型中使用 belongs_to
和 has_many
方法來實現 Self Joins。具體實現方式是,在模型中定義一個外來鍵欄位來引用自身的 ID,然後透過 belongs_to
方法宣告自身與父級的關聯,再透過 has_many
方法宣告自身與子級的關聯。
下面是一個簡單的例子,假設有一個 Category
模型,每個分類可以有多個子分類,同時也可以屬於一個父分類:
class Category < ApplicationRecord
belongs_to :parent, class_name: 'Category', optional: true
has_many :children, class_name: 'Category', foreign_key: 'parent_id'
end
上面的程式碼中,Category
模型透過 belongs_to
方法宣告與父級的關聯,使用 class_name
選項指定關聯的模型名稱為 Category
,同時使用 optional: true
選項表示父級可以為空。透過 has_many
方法宣告與子級的關聯,使用 class_name
選項指定關聯的模型名稱為 Category
,使用 foreign_key
選項指定外來鍵欄位為 parent_id
。
在資料庫中,需要建立一個 categories
表來儲存分類。該表需要包含一個 parent_id
欄位用於儲存父級分類的 ID,可以使用以下程式碼建立 categories
表:
rails generate migration CreateCategories name:string parent:references
上面的程式碼將生成一個名為 CreateCategories
的遷移檔案,該檔案將建立一個 categories
表,並新增一個 name
欄位用於儲存分類名稱,以及一個 parent_id
欄位用於儲存父級分類的ID。
可以使用以下程式碼來訪問一個分類的父級:
category.parent
可以使用以下程式碼來訪問一個分類的子級:
category.children
總之,Self Joins 允許在一個表中透過外來鍵關聯自身的另一行資料,常用於需要建立層次結構的資料模型。在 Rails 中,可以透過在模型中使用 belongs_to
和 has_many
方法來實現 Self Joins,透過定義一個外來鍵欄位來引用自身的 ID,然後宣告自身與父級的關聯和自身與子級的關聯。
Tips, Tricks, and Warnings
Controlling Caching
# retrieves books from the database
author.books.load
# uses the cached copy of books
author.books.size
# uses the cached copy of books
author.books.empty?
這是關於 ActiveRecord 的程式碼示例,它展示瞭如何使用快取來訪問一個作者(author)的書籍(books)。
第一行程式碼 author.books.load
從資料庫中檢索作者的書籍,並將其儲存在快取中。這意味著在下一行程式碼和之後的程式碼中,將使用快取中的書籍,而不是從資料庫中再次檢索它們。
第二行程式碼 author.books.size
返回快取中作者的書籍數量,而不是從資料庫中再次檢索它們。這是因為在第一行程式碼中,author.books.load
將書籍儲存在快取中,因此在下一行程式碼中,可以直接從快取中獲取書籍數量,而不需要從資料庫中再次檢索它們。
第三行程式碼 author.books.empty?
返回一個布林值,指示快取中作者的書籍是否為空。同樣地,這是因為在第一行程式碼中,author.books.load
將書籍儲存在快取中,因此在第三行程式碼中,可以直接從快取中檢查書籍是否為空,而不需要從資料庫中再次檢索它們。
這種使用快取的方式可以幫助提高應用程式的效能,因為它避免了在每次訪問物件時都需要從資料庫中檢索資料的開銷。但是,需要注意的是,如果在快取中的資料與資料庫中的資料不同步,則可能會導致資料不一致。因此,在使用快取時,需要仔細考慮如何更新快取以確保資料的正確性。
Creating Foreign Keys for belongs_to Associations
在關係型資料庫中,外來鍵(Foreign Key)是一種用於建立表之間關聯的技術。當一個表中的列引用另一個表的主鍵時,就會建立一個外來鍵。在 Rails 中,透過使用 belongs_to
關聯,可以輕鬆地建立外來鍵。以下是一個實際的示例:
假設您正在構建一個部落格應用程式,其中包含多個文章(Post)和多個評論(Comment)。每個評論都屬於一個特定的文章,因此您需要在評論表中建立一個外來鍵,以引用文章表中的主鍵。
首先,您需要在 Comment
模型中新增一個 belongs_to
關聯:
class Comment < ApplicationRecord
belongs_to :post
end
然後,您需要在評論表中新增一個名為 post_id
的整數列,用於儲存文章的主鍵值。在 Rails 中,可以使用資料庫遷移來新增此列:
rails generate migration AddPostIdToComments post:references
這將生成一個包含 add_reference
方法的遷移檔案,該方法將在評論表中新增一個 post_id
列,並將其設定為引用文章表的主鍵。
最後,您需要執行遷移,以將更改應用於資料庫:
rake db:migrate
現在,當您建立一個新評論時,Rails 將自動在評論表中設定正確的 post_id
值,以引用相應的文章。
例如,您可以透過以下程式碼將一條評論關聯到一篇文章:
post = Post.first
post.comments.create(body: "Great post!")
這是一個示例程式碼,用於在 Rails 應用程式中建立新評論並將其與特定文章關聯。
首先,Post.first
獲取文章表中的第一篇文章,並將其分配給變數 post
。然後,post.comments.create
用於建立一個新評論,並將其與 post
變數中儲存的文章關聯起來。這是透過 has_many :comments
關聯和 Comment
模型中的 belongs_to :post
關聯實現的。
具體來說,post.comments
返回一個關聯物件,該物件允許您訪問與特定文章相關聯的所有評論。然後,create
方法用於建立一個新評論,並將其與 post
關聯起來。在本例中,新評論的 body
屬性設定為 "Great post!"
。
最後,新評論將被儲存到資料庫中,並且在 comments
表中將包含一個新行,其中包含評論的內容和與之相關聯的文章的主鍵值。
這是一個典型的 Rails 應用程式中的程式碼示例,用於演示如何使用關聯模型和建立新物件。
Creating Join Tables for has_and_belongs_to_many Associations
在 Rails 中,has_and_belongs_to_many
(HABTM)關聯用於建立多對多的關係。在關係型資料庫中,通常需要使用一箇中間表來儲存這種關聯,這個中間表被稱為“聯接表”(Join Table)。
建立聯接表的步驟如下:
-
建立一個名為
table1_table2
的表,其中table1
和table2
分別是要關聯的兩個表的名稱。例如,如果您想要關聯users
和groups
表,則可以建立一個名為users_groups
的聯接表。 -
新增兩個整數列,分別用於儲存關聯表的主鍵。這些列通常被命名為
table1_id
和table2_id
,例如user_id
和group_id
。 -
向
table1
和table2
中的模型檔案中新增has_and_belongs_to_many
關聯。例如,在User
模型中,您可以這樣新增一個has_and_belongs_to_many
關聯:
class User < ApplicationRecord
has_and_belongs_to_many :groups
end
這將指示 Rails 透過 users_groups
表將 users
和 groups
表關聯起來。
以下是一個實際的示例:
假設您正在構建一個社交網路應用程式,其中使用者(User)可以加入多個組(Group),而每個組也可以有多個使用者。為了實現這種多對多關係,您需要建立一個聯接表。
首先,您可以使用以下命令建立一個名為 groups_users
的聯接表:
rails generate migration CreateGroupsUsers
然後,您可以使用以下程式碼向遷移檔案中新增表的定義:
class CreateGroupsUsers < ActiveRecord::Migration[6.1]
def change
create_table :groups_users, id: false do |t|
t.references :group, null: false, foreign_key: true
t.references :user, null: false, foreign_key: true
end
end
end
這將建立一個名為 groups_users
的聯接表,並新增 group_id
和 user_id
兩個整數列,用於儲存關聯表的主鍵。
最後,您可以向 User
和 Group
模型中新增 has_and_belongs_to_many
關聯,以指示它們之間的多對多關係:
class User < ApplicationRecord
has_and_belongs_to_many :groups
end
class Group < ApplicationRecord
has_and_belongs_to_many :users
end
現在,您可以使用 <<
運算子向使用者新增組,例如:
user = User.first
group = Group.first
user.groups << group
這將將 user
和 group
關聯起來,並在 groups_users
表中新增一個新行,其中包含 user_id
和 group_id
的值。
透過使用 has_and_belongs_to_many
關聯和聯接表,您可以輕鬆地建立多對多關係,並在 Rails 應用程式中儲存和檢索相關資料。
Controlling Association Scope
在 Rails 中,可以使用 scope
方法來控制關聯模型的查詢範圍。這可以幫助您過濾不必要的資料,以提高應用程式的效能和可維護性。
例如,假設您正在構建一個電子商務應用程式,其中訂單(Order)有多個訂單項(OrderItem),並且每個訂單項都屬於一個特定的產品(Product)。現在,您想要檢索某個產品的所有訂單項。
首先,您可以在 Product
模型中新增一個 has_many
關聯,以指示每個產品都有多個訂單項:
class Product < ApplicationRecord
has_many :order_items
end
然後,您可以使用 scope
方法來指定只檢索與特定產品相關聯的訂單項:
class OrderItem < ApplicationRecord
belongs_to :product
scope :for_product, -> (product) { where(product_id: product.id) }
end
這將建立一個名為 for_product
的作用域,它接受一個產品物件作為引數,並返回與該產品相關聯的所有訂單項。
現在,您可以在控制器或檢視中使用 for_product
作用域來檢索與特定產品相關聯的所有訂單項。例如,假設您正在顯示某個產品的詳細資訊,並想要列出所有相關的訂單項:
def show
@product = Product.find(params[:id])
@order_items = OrderItem.for_product(@product)
end
這將檢索與 @product
相關聯的所有訂單項,並將它們分配給 @order_items
變數。由於使用了作用域,查詢將僅返回與特定產品相關聯的訂單項,而不是所有訂單項,從而提高了查詢的效能和可維護性。
透過使用作用域方法,您可以輕鬆地控制關聯模型的查詢範圍,並過濾不必要的資料,以提高應用程式的效能和可維護性。
Bi-directional Associations
在 Rails 中,雙向關聯(Bi-directional Associations)是指兩個關聯模型之間的相互關係,其中每個模型都可以訪問另一個模型。這可以透過在兩個模型中都定義關聯來實現。
例如,假設您正在構建一個部落格應用程式,其中文章(Post)可以有多個標籤(Tag),而每個標籤也可以與多篇文章相關聯。為了實現這種雙向關聯,您可以在 Post
和 Tag
模型中都定義一個關聯。
首先,您可以在 Post
模型中新增一個 has_and_belongs_to_many
關聯,以指示每篇文章都可以有多個標籤:
class Post < ApplicationRecord
has_and_belongs_to_many :tags
end
然後,您可以在 Tag
模型中新增一個相反的 has_and_belongs_to_many
關聯,以指示每個標籤也可以與多篇文章相關聯:
class Tag < ApplicationRecord
has_and_belongs_to_many :posts
end
現在,您可以在控制器或檢視中使用這些關聯來訪問相互關聯的模型。例如,假設您想要列出所有帶有特定標籤的文章:
def index
@tag = Tag.find(params[:tag_id])
@posts = @tag.posts
end
這將檢索與 @tag
相關聯的所有文章,並將它們分配給 @posts
變數。由於使用了雙向關聯,您可以透過 @tag.posts
訪問所有相關的文章,也可以透過 @post.tags
訪問所有相關的標籤。
雙向關聯使得在兩個關聯模型之間進行導航變得非常容易。透過在每個模型中都定義關聯,您可以輕鬆地訪問相互關聯的資料,並簡化程式碼的編寫和維護。
Detailed Association Reference
belongs_to Association Reference
這些方法都是 ActiveRecord 中用於操作關聯關係的方法,主要用於設定、建立、檢索和重新載入關聯物件。下面是這些方法的解釋:
-
association
:獲取關聯物件。例如,如果Book
模型與Author
模型存在belongs_to
關聯關係,則可以使用book.author
獲取與該書籍關聯的作者物件。 -
association=(associate)
:設定關聯物件。例如,如果Book
模型與Author
模型存在belongs_to
關聯關係,則可以使用book.author = author
將book
物件與特定的author
物件關聯起來。 -
build_association(attributes = {})
:建立一個新的關聯物件,並將其與當前物件關聯起來。例如,如果Book
模型與Author
模型存在has_one
關聯關係,則可以使用book.build_author(author_name: "John Doe")
建立一個新的Author
物件,並將其與book
物件關聯起來。 -
create_association(attributes = {})
:建立一個新的關聯物件,並將其與當前物件關聯起來,然後將其儲存到資料庫中。例如,如果Book
模型與Author
模型存在has_many
關聯關係,則可以使用book.authors.create(author_name: "John Doe")
建立一個新的Author
物件,並將其與book
物件關聯起來,然後將其儲存到資料庫中。 -
create_association!(attributes = {})
:與create_association
方法類似,但是如果建立失敗(例如,因為驗證失敗),則會引發異常。 -
reload_association
:重新載入關聯物件,並將其與資料庫中的最新資料同步。例如,如果您對關聯物件進行了更改,並希望檢索最新版本,則可以使用book.author.reload_association
重新載入與該書籍關聯的作者物件。 -
association_changed?
:檢查關聯物件是否已更改。例如,如果您更改了與book
物件關聯的author
物件,則可以使用book.author_changed?
檢查是否更改了該物件。 -
association_previously_changed?
:檢查關聯物件在上一次儲存時是否已更改。例如,如果您想知道與book
物件關聯的author
物件在上一次儲存時是否已更改,則可以使用book.author_previously_changed?
檢查。