Active Record Associations

Giới thiệu

Trong rails, association là liên kết giữa 2 model với nhau. Association giúp cho việc truy vấn dễ dàng và làm cho code ngắn gọn, đơn giản hơn rất nhiều. Giả sử ta có 2 models là User và Picture, giả sử 1 user có nhiều picture và 1 picture chỉ thuộc 1 user. Khi đó ta sẽ khai báo trong model User và Picture như sau:

class User < ApplicationRecord
    has_many :pictures
end
 
class Picture < ApplicationRecord
    belongs_to :user
end

Khi chúng ta đã có 1 user hay 1 picture bất kỳ, việc tìm ra các pictures hay user của nó rất dễ dàng, bằng dòng code như sau:

user = User.first #giả sử user tồn tại
pictures = user.pictures

hoặc:

picture = Picture.first #giả sử picture tồn tại
user = picture.user

Các loại Associations

Rails có hỗ trợ 6 loại như sau:

  1. belongs_to
  2. has_one
  3. has_many
  4. has_many :through
  5. has_one :through
  6. has_and_belongs_to_many

The belongs_to association

belongs_to thiết lập kết nối one-to-one (1-1) giữa model này với model khác. Giả sử như ví dụ ở trên ta khai báo trong model Picture

belongs_to :user

Đặc biệt, đối với belongs_to chúng ta cần khai báo khóa ngoại cho bảng. Giả sử trong trường hợp này, chúng ta cần có khóa ngoại user_id trong bảng pictures.

class CreateTables < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      t.string :name
      t.timestamps
    end
 
    create_table :pictures do |t|
      t.belongs_to :users, index: true
      t.string :name
      t.timestamps
    end
  end
end

The has_one Association

has_one cũng thiết lập kết nối one-to-one với 1 model khác, nhưng nó khác nhau về mặt ý nghĩa. Mối quan hệ này cho thấy răng 1 đối tượng của model này sở hữu 1 đối tượng của model khác. Ví dụ như ta có 2 đối tượng của 2 models là user và account, mỗi user chỉ có một account. Chúng ta sẽ khai báo như sau:

class User < ApplicationRecord
  has_one :account
end
class CreateTables < ActiveRecord::Migration[5.0]
  def change
    create_table :users do |t|
      t.string :name
      t.timestamps
    end
 
    create_table :accounts do |t|
      t.belongs_to :user, index: true, unique: true, foreign_key: true
      t.string :account_number
      t.timestamps
    end
  end
end

Tùy vào trường hợp và mục đích sử dụng, chúng ta có thể khai báo unique hay không.

The has_many Association

has_many thiết lập kết nối one-to-many với 1 model khác. Chúng ta sẽ thường thấy has_many ở model kia trong mối quan hệ belongs_to. Mối quan hệ này chỉ ra răng một đối tượng của model này có thể có 0 hoặc nhiều đối tượng của một model khác. Ví dụ như ở trên, ta có một user sẽ có nhiều pictures, ta sẽ khai báo như sau:

class User < ApplicationRecord
    has_many :pictures
end
 
class Picture < ApplicationRecord
    belongs_to :user
end

Ở model Picture, chúng ta có khai báo quan hệ belongs_to vậy nên chúng ta cần phải thêm khóa ngoại user_id cho bảng pictures.

class CreateTables < ActiveRecord::Migration[5.0]
  def change
      create_table :users do |t|
      t.string :name
      t.timestamps
    end
 
    create_table :pictures do |t|
      t.belongs_to :user, index: true
      t.string :name
      t.timestamps
    end
  end
end

The has_many :through Association

has_many:through association thường được sử dụng để thiết lập mối quan hệ many-to-many (n-n) giữa 2 model với nhau. Giả sử ta có 2 model Student và Subject, trong đó 1 học sinh có thể học nhiều môn và 1 môn học có thể có nhiều học sinh học. Từ đó ta có quan hệ giữa Student và Subject là n-n. Thông thường, đối với quan hệ n-n, chúng ta cần tạo ra 1 model thứ 3 ở giữa để trở thành 2 mối quan hệ 1-n. Trong trường hợp này, chúng ta sẽ có model thứ 3 chính là Result và khai báo trong các model như sau:

class Student < ApplicationRecord
  has_many :results
  has_many :subjects, through: :results
end
 
class Result < ApplicationRecord
  belongs_to :student
  belongs_to :subject
end
 
class Subject < ApplicationRecord
  has_many :results
  has_many :students, through: :results
end

The has_one :through Association

has_one :through association thiết lập quan hệ one-to-one giữa model này với model khác. Quan hệ này chỉ ra mối quan hệ 1-1 giữa model này với 1 model khác thông qua 1 model thứ 3. Giả sử nếu như chúng ta có model Supplier sẽ có quan hệ 1-1 với model Account và model Account có quan hệ 1-1 với AccountHistory. Từ đó, thông qua model Account chúng ta sẽ có ứng với 1 Supplier sẽ có 1 AccountHistory. Và chúng ta khai báo trong model như sau:

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

The has_and_belongs_to_many Association

has_and_belongs_to_many tạo ra một quan hệ n-n trực tiếp mà không có sự can thiệp của 1 model khác. Giả sử chúng ta có model Assembly và Part. Ứng với 1 assembly có nhiều parts và 1 part có nhiều assemblies. Chúng ta sẽ khai báo trong model như sau:

class Assembly < ApplicationRecord
  has_and_belongs_to_many :parts
end
 
class Part < ApplicationRecord
  has_and_belongs_to_many :assemblies
end

Kết

Trên đây mình giới thiệu với các bạn về mối quan hệ giữa các ActiveRecord trong Rails, tất nhiên vẫn còn nhiều thiếu sót và hạn chế, hy vọng giúp ích phần nào và các bạn tiếp cận Rails dễ dàng hơn.

Tham khảo:

http://guides.rubyonrails.org/association_basics.html