12/08/2018, 14:16

ActiveRecord Assocations

Với Associations (liên kết), việc thực hiện nhiều phép tính lên các record trong code của bạn trở nên vô cùng dễ dàng. Có nhiều kiểu liên kết bạn có thể sử dụng: One-to-one (một-một) One-to-many (một-nhiều) Many-to-many (nhiều-nhiều) Polymorphic one-to-many (đa dạng-nhiều) 1. Liên kết ...

Với Associations (liên kết), việc thực hiện nhiều phép tính lên các record trong code của bạn trở nên vô cùng dễ dàng. Có nhiều kiểu liên kết bạn có thể sử dụng:

  • One-to-one (một-một)
  • One-to-many (một-nhiều)
  • Many-to-many (nhiều-nhiều)
  • Polymorphic one-to-many (đa dạng-nhiều)

1. Liên kết một - nhiều

Liên kết một-nhiều có lẽ là kiểu liên kết được sử dụng rộng rãi nhất. Ý niệm khá đơn giản: record A có nhiều record B và record B chỉ thuộc về một record A duy nhất. Với mỗi record B, bạn sẽ phải lưu trữ một id của record A sở hữu record B này, id này được gọi là foreign key.

Giả dụ, ta có một user, user này có thể có nhiều post.

  class User < ApplicationRecord
    has_many :posts
  end
class Post < ApplicationRecord
  belongs_to :user
end

Khi đã thiết lập quan hệ, bạn có thể sử dụng method như:

  • user.posts – tham chiếu posts của user
  • user.posts << post – thiết lập quan hệ mới giữa một user và một post
  • post.user – tham chiếu người sở hữu post
  • user.posts.build({ }) – khởi tạo post mới cho user, nhưng vẫn chưa lưu vào database. Nhưng có populate user_id attribute trên post. Cái này cũng giống như Post.new({user_id: user.id}).
  • user.posts.create({ }) – tạo post mới và lưu vào database.

Với liên kết has_many, vẫn còn có tùy chỉnh :class_name và :foreign_key dùng được.Bạn có thể set một tùy chọn khác là :dependent, thường cho mối quan hệ has_many. Tại sao ta cần đến nó? Giả sử, một user có rất nhiều post. Khi user đó bị xóa khỏi database . Vậy những post của user này gọi là orphaned và có thể dẫn đến rất nhiều vấn đề, vậy nên bạn có lẽ sẽ muốn xử lý nhanh những tình huống như thế này đấy.

Tùy chọn :dependent chấp nhận những giá trị sau:

  • :destroy – tất object được liên kết lần lượt bị loạt bỏ (trong query riêng). Những callbacks phù hợp sẽ chạy trước và sau khi loại bỏ.
  • :delete_all – Tất cả object được liên kết sẽ bị xóa bỏ trong một query duy nhất. Sẽ không có callback nào được thực thi.
  • :nullify – foreign keys cho các objects được liên kết sẽ set về NULL. Sẽ không có callback nào được thực thi.
  • :restrict_with_exception – Nếu có record được liên kết, sẽ xuất hiện exception.
  • :restrict_with_error – Nếu có record liên kết, sẽ thêm một error vào người sỡ hữu (the record bạn đang cố xóa).

2. Liên kết một - một

Với quan hệ một-một bạn cơ bản có thể hiểu rằng một record chứa chính xác một instance của một model khác. Ví dụ như, hãy lưu trữ địa chỉ người dùng trong một bảng tách riêng gọi là addresses. Bảng này phải chứa một foreign key, mặc định đặt tên theo quan hệ

 class User < ApplicationRecord
   has_one :address
 end

bạn có thể call một số methods như

  • user.address – truy xuất địa chỉ liên quan
  • user.build – tương tự như method của belongs_to; thực thể hóa (instantiate) địa chỉ mới, nhưng không lưu vào database.
  • user.create – thực thể hóa địa chỉ mới, lưu vào database.

Quan hệ has_one cho phép bạn xác định :class_name, :dependent, foreign_key, và nhiều tùy chọn khác, giống has_many

3. Liên kết nhiều - nhiều

a, Liên kết “Has and Belongs to Many”

Giả sử, một user có thể enroll vào nhiều event khác nhau và một event có thể chứa nhiều user. Để đạt được mục tiêu này, chúng ta cần một table riêng biệt (thường gọi là “join table”) chứa quan hệ giữa user và event. Table này phải có một tên đặc biệt: users_events. Về cơ bản, đây chỉ là kết hợp giữa hai tên table mà ta đang tạo quan hệ . Chú ý tên của table trung gian – Rails muốn tên này gồm tên của hai table (events và users). Hơn nữa, tên bậc cao (events) nên đứng trước (events > users, vì chữ cái “e” đứng trước chữ “u”)

 class User < ApplicationRecord
   has_and_belongs_to_many :events
 end
 class Event < ApplicationRecord
   has_and_belongs_to_many :users
 end

Bạn có thể call các method như:

  • user.events
  • user.events << [event1, event2] – tạo quan hệ giữa một người dùng và một loạt events
  • user.events.destroy(event1) – hủy quan hệ giữa các records (sẽ không xóa records thật). Vẫn còn một delete method có tác dụng tương tự, nhưng lại không chạy được callbacks
  • user.event_ids – một method gọn gàng, giúp trả một array ids từ collection
  • user.event_ids = [1,2,3] – làm collection chỉ chứa các objects do các key values chính (được cung cấp) xác định.
  • Lưu ý, nếu collection ban đầu chứa các objects khác, những objects này sẽ bị loại bỏ.
  • user.events.create({}) – tạo object mới và thêm object vào collection.

b, Liên kết “Has Many Through”

Một cách xác định liên kết nhiều-nhiều nữa là sử dụng loại liên kết has many through. Giả sử ta có một loạt game, và mỗi một đoạn thời gian, những cuộc thi đấu của game này sẽ được tổ chức. Nhiều user có thể tham gia vào nhiều cuộc thi. Bên cạnh việc thiết đặt mối quan hệ nhiều-nhiều giữa user và game, ta còn muốn lưu trữ thông tin bổ sung về mỗi enrollment, như loại cuộc thi (nhiệp dư, semi-pro, pro,…)

 class User < ApplicationRecord
   has_many :enrollments
   has_many :games, through: :enrollments
 end
 class Game < ApplicationRecord
   has_many :enrollments
   has_many :users, through: :enrollments
 end
 class Enrollment < ApplicationRecord
   belongs_to :game
   belongs_to :user
 end

Ở đây, ta chỉ định rõ model trung gian để thiết lập quan hệ này. Đến đây bạn có thể làm việc với mỗi enrollment như một thực thể độc lập

Hy vọng bài viết sẽ giúp ích cho bạn

0