Một vài vấn đề về Active Record Associations
Bài đăng này đã không được cập nhật trong 6 năm
Trong Rails, association
là một kết nối giữa hai Active Record models. Chúng ta sử dụng association
giữa hai models để làm các hàm, các biểu thức, phép tính trong code trở lên đơn giản hơn.
1. Các loại quan hệ
Rails support 6 loại quan hệ:
- belongs_to
- has_one
- has_many
- has_many :through
- has_one :through
- has_and_belongs_to_many
1.1 belongs_to
belongs_to
là quan hệ một - một giữa 2 model, sao cho mỗi cá thể của model này thuộc về 1 cá thể của model kia.
Ví dụ chúng ta có 2 model là Author và Book. Mỗi book thuộc về 1 author. Trong model Book ta sẽ khai báo:
class Book < ApplicationRecord
belongs_to :author
end
! Chú ý khi khai báo belongs_to
phải sử dụng từ số ít.
1.2 has_one
has_one
cũng là quan hệ một - một, nhưng về ngữ nghĩa sẽ ngược với belongs_to
về model sở hữu và bị sở hữu.
Ví dụ 1 supplier có 1 account:
class Supplier < ApplicationRecord
has_one :account
end
1.3 has_many
has_many
là quan hệ một - nhiều với model. Nó thường đi kèm với quan hệ belongs_to
ở phía model kia. Nó chỉ ra 1 cá thể của model này có thể không có hoặc có nhiều cá thể của model kia.
Ví dụ 1 author có thể có nhiều book.
class Author < ApplicationRecord
has_many :books
end
! Chú ý khi khai báo has_many
cần sử dụng từ dạng số nhiều.
1.4 has_many :through
has_many :through
thường xuyên được sử dụng để tạo quan hệ nhiều - nhiều với model khác. Nó cho phép 1 cá thể của model này liên kết với nhiều cá thể của model khác thông qua một model thứ 3.
Ví dụ trong một buổi khám sức khỏe tổng quát. Mỗi bệnh nhân (patient) sẽ lần lượt xếp hàng để đợi đến những lượt khám (appointment) để gặp các bác sĩ (physician). Như vậy mỗi lượt khám, 1 bệnh nhân sẽ gặp 1 bác sĩ. Như vậy cả buổi khám, 1 bênh nhân sẽ gặp nhiều bác sĩ và 1 bác sĩ sẽ khám cho nhiều bệnh nhân.
class Physician < ApplicationRecord
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ApplicationRecord
belongs_to :physician
belongs_to :patient
end
class Patient < ApplicationRecord
has_many :appointments
has_many :physicians, through: :appointments
end
has_many :through
cũng có thể dùng để tạo quan hệ has_many
lồng nhau.
Ví dụ mỗi document có nhiều section, mỗi section lại có nhiều paragraph.
class Document < ApplicationRecord
has_many :sections
has_many :paragraphs, through: :sections
end
class Section < ApplicationRecord
belongs_to :document
has_many :paragraphs
end
class Paragraph < ApplicationRecord
belongs_to :section
end
1.5 has_one :through
Đây là quan hệ một - một. Nó chỉ ra 1 cá thể của model này liên kết với 1 cá thể của model khác thông qua một model thứ 3. Ví dụ:
class Supplier < ApplicationRecord
has_one :account
has_one :account_history, through: :account
end
class Account < ApplicationRecord
belongs_to :supplier
has_one :account_history
end
class AccountHistory < ApplicationRecord
belongs_to :account
end
1.6 has_and_belongs_to_many
has_and_belongs_to_many
là quan hệ nhiều - nhiều.
Ví dụ:
class Assembly < ApplicationRecord
has_and_belongs_to_many :parts
end
class Part < ApplicationRecord
has_and_belongs_to_many :assemblies
end
! Tuy không cần khai báo model phụ của 2 model này những vẫn cần tạo assemblies_parts
.
2. Lựa chọn giữa belongs_to và has_one
Khi xây dựng quan hệ một - một ta cần thêm belongs_to
vào một model và has_one
vào một model. Vậy làm cách nào ta biết thêm cái nào vào đâu.
Nếu đã có sẵn cơ sở dữ liệu thì ta sẽ dựa vào khóa ngoài (foreign key), nó nằm ở bảng nào thì model đó sẽ đặt quan hệ belongs_to
. Tuy nhiêu khi cần xây dựng cơ sở dữ liệu thì ta cần dự vào ý nghĩa thực tế để xác định.
Ví dụ với 2 thứ là Người và Tên. Theo đúng ý nghĩa thì mỗi người có một (has_one) tên, và mỗi tên thuộc về (belongs_to) một người.
3. Lựa chọn giữa has_many :through và has_and_belongs_to_many
Đây đều là quan hệ nhiều nhiều.
Với has_and_belongs_to_many
class Assembly < ApplicationRecord
has_and_belongs_to_many :parts
end
class Part < ApplicationRecord
has_and_belongs_to_many :assemblies
end
Với has_many :through
class Assembly < ApplicationRecord
has_many :manifests
has_many :parts, through: :manifests
end
class Manifest < ApplicationRecord
belongs_to :assembly
belongs_to :part
end
class Part < ApplicationRecord
has_many :manifests
has_many :assemblies, through: :manifests
end
Để lựa chọn, đơn giản nhất là dựa vào ứng dụng của model quan hệ thứ 3. Nếu nó chỉ đơn thuần để liên kết 2 model chính và không còn tác dụng gì khác thì ta nên dùng has_and_belongs_to_many
, còn nếu ta cần sử dụng nó vào nhiều mục đích khác thì nên dùng has_many :through
4. Controlling Caching
Tất cả các association methods
đều được xây dựng xung quang bộ nhớ đệm, cái mà sẽ giữ kết quả của lần query gần nhất cho những tính toán tương tự về sau. Cache có thể chia sẽ giữa các hàm trong controller.
Ví dụ:
author.books # lấy ra books từ trong cơ sở dữ liệu
author.books.size # sử dụng lại books đã lưu cache
author.books.empty? # sử dụng lại books đã lưu cache
Nếu bán muốn reload cache vì có thể dữ liệu đã bị thay đổi ở chỗ nào đó thì bạn có thể dùng hàm reload
.
author.books # lấy ra books từ trong cơ sở dữ liệu
author.books.size # sử dụng lại books đã lưu cache
author.books.reload.empty? # loại bỏ cache đã lưu books và lấy ra lại từ cơ sở dữ liệu
All rights reserved