主頁 > 後端開發 > Active Record Associations

Active Record Associations

2023-04-22 07:31:20 後端開發

The Types of Associations

在 Rails 中,可以通過 ActiveRecord 來定義不同型別的關聯關系(Associations),包括以下幾種:

  1. belongs_to:表示該模型 belongs_to 另一個模型,即該模型擁有一個外鍵(foreign key)指向另一個模型的主鍵(primary key),通常用于表示一對一或多對一的關系,

  2. has_one:表示該模型 has_one 另一個模型,即另一個模型擁有一個外鍵指向該模型的主鍵,通常用于表示一對一的關系,

  3. has_many:表示該模型 has_many 另一個模型,即另一個模型擁有一個外鍵指向該模型的主鍵,通常用于表示一對多的關系,

  4. has_many :through:表示通過中間模型建立多對多的關系,通常用于表示多對多的關系,

  5. has_one :through:表示通過中間模型建立一對一或多對一的關系,

  6. 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

這是一個創建 authorsbooks 兩個資料庫表的遷移檔案,authors 表包含一個 name 欄位和 created_atupdated_at 兩個時間戳欄位,books 表包含一個 author_id 外鍵欄位來關聯 authors 表,一個 published_at 欄位和 created_atupdated_at 兩個時間戳欄位,

在 Rails 中,遷移檔案用于創建、修改和洗掉資料庫表和欄位,這個遷移檔案中的 change 方法定義了如何創建 authorsbooks 兩個表,在 create_table 塊中,我們可以宣告表中的欄位和型別,以及其他選項,如外鍵關聯等,在這個例子中,我們使用 belongs_to 方法來宣告 books 表與 authors 表之間的關聯關系,

當我們運行這個遷移檔案時,Rails 將會執行 change 方法中的代碼,并在資料庫中創建 authorsbooks 兩個表,同時,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_manyhas_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_tohas_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 :throughhas_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 模型,它可以屬于多個其他模型(例如 PostPhoto),同時這些其他模型也可以有多個評論:

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 是一個多型關聯欄位,它可以屬于任何其他模型,在 PostPhoto 模型中,使用 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_tohas_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_tohas_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),

創建聯接表的步驟如下:

  1. 創建一個名為 table1_table2 的表,其中 table1table2 分別是要關聯的兩個表的名稱,例如,如果您想要關聯 usersgroups 表,則可以創建一個名為 users_groups 的聯接表,

  2. 添加兩個整數列,分別用于存盤關聯表的主鍵,這些列通常被命名為 table1_idtable2_id,例如 user_idgroup_id

  3. table1table2 中的模型檔案中添加 has_and_belongs_to_many 關聯,例如,在 User 模型中,您可以這樣添加一個 has_and_belongs_to_many 關聯:

class User < ApplicationRecord
  has_and_belongs_to_many :groups
end

這將指示 Rails 通過 users_groups 表將 usersgroups 表關聯起來,

以下是一個實際的示例:

假設您正在構建一個社交網路應用程式,其中用戶(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_iduser_id 兩個整數列,用于存盤關聯表的主鍵,

最后,您可以向 UserGroup 模型中添加 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

這將將 usergroup 關聯起來,并在 groups_users 表中添加一個新行,其中包含 user_idgroup_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),而每個標簽也可以與多篇文章相關聯,為了實作這種雙向關聯,您可以在 PostTag 模型中都定義一個關聯,

首先,您可以在 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 = authorbook 物件與特定的 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? 檢查,

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/550770.html

標籤:其他

上一篇:jdk1.8 LocalTime、LocalDate、LocalDateTime 使用大全

下一篇:返回列表

標籤雲
其他(157783) Python(38089) JavaScript(25379) Java(17985) C(15215) 區塊鏈(8256) C#(7972) AI(7469) 爪哇(7425) MySQL(7135) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4555) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1959) Web開發(1951) python-3.x(1918) HtmlCss(1917) 弹簧靴(1913) C++(1910) xml(1889) PostgreSQL(1872) .NETCore(1854) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Active Record Associations

    The Types of Associations 在 Rails 中,可以通過 ActiveRecord 來定義不同型別的關聯關系(Associations),包括以下幾種: belongs_to:表示該模型 belongs_to 另一個模型,即該模型擁有一個外鍵(foreign key)指向另一 ......

    uj5u.com 2023-04-22 07:31:20 more
  • jdk1.8 LocalTime、LocalDate、LocalDateTime 使用大全

    LocalTime、LocalDate、LocalDateTime 區別 LocalTime、LocalDate、LocalDateTime是java8對日期、時間提供的新介面。 jdk1.8 之前的 SimpleDateFormat 是執行緒不安全的。 DateTimeFormatter是執行緒安全的 ......

    uj5u.com 2023-04-22 07:31:14 more
  • SpringBoot自定義cron運算式注冊定時任務

    springBoot自定義cron運算式注冊定時任務 一、原理 1、使用Spring自帶的TaskScheduler注冊任務 2、注冊后回傳:ScheduledFuture,用于取消定時任務 3、注冊任務后不會馬上取消任務,所以將任務快取。在需要取消任務的時候呼叫取消介面取消 4、cron運算式可以 ......

    uj5u.com 2023-04-22 07:31:08 more
  • 從原理聊JVM(一):染色標記和垃圾回收演算法

    本篇介紹了JVM中垃圾回收器相關的基礎知識,后續會深入介紹CMS、G1、ZGC等不同垃圾收集器的運作流程和原理,歡迎關注。 ......

    uj5u.com 2023-04-22 07:30:35 more
  • 記一次jedis連接池頑固問題排查與修改

    這輩子不想再看到jedisBrokenPipe!! 測驗環境運行16天后報錯資訊: 05:42:32.629 [http-nio-8093-exec-2] ERROR o.a.c.c.C.[.[.[.[dispatcherServlet] - [log,175] - Servlet.service( ......

    uj5u.com 2023-04-22 07:30:16 more
  • 我的OpenAI庫發布了!!!

    chatGPT正式發布已經有段時間了,這段時間我也深度體驗了chatGPT的魅力。 OpenAI除了提供網頁版的chatGPT,還通過api的形式提供了很多其它服務,包括文字糾錯、圖片生成、音頻轉換等等。 作為程式員,即使有現成的openai庫,但還是免不了想自己造輪子,所以就有這個openai庫。 ......

    uj5u.com 2023-04-22 07:30:10 more
  • MDC輕量化日志鏈路跟蹤的若干種應用場景

    "If debugging is the process of removing software bugs, then programming must be the process of putting them in." - Edsger Dijkstra “如果除錯是消除軟體Bug的程序,那 ......

    uj5u.com 2023-04-22 07:30:06 more
  • WCF教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows通訊開發平臺(Windows Communication Foundation,簡稱WCF)是由微軟開發的一系列支持資料通信的應用程式框架,可以翻譯為Windows通訊開發平臺。 整合了原有的windows通訊的 .net Remoting,WebService,Socket ......

    uj5u.com 2023-04-22 07:30:01 more
  • Django筆記二十七之資料庫函式之文本函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十七之資料庫函式之文本函式 這篇筆記將介紹如何使用資料庫函式里的文本函式。 顧名思義,文本函式,就是針對文本欄位進行操作的函式,如下是目錄匯總: Concat() —— 合并 Left() —— 從左邊開始截取 Length() —— ......

    uj5u.com 2023-04-22 07:29:19 more
  • 圖片的腐蝕,膨脹,開丶閉運算,梯度計算,禮帽與黑帽

    1 腐蝕操作 用于圖片的去毛刺,內容削減 1 #腐蝕操作 2 #cv2.erode(src,kernel,iterations) 3 #src是圖片數字化陣列 4 #kernel則是一個盒,對該盒內的像素進行復試操作,值越小腐蝕能力越狠 5 #iterations是一個迭代次數,就是說你對這個圖片進 ......

    uj5u.com 2023-04-22 07:29:14 more