12/08/2018, 17:27

Một vài vấn đề về Active Record Associations (Phần 2)

Phần này mình sẽ giới thiệu chi tiết về: belongs_to association association=(associate) build_association(attributes = {}) create_association(attributes = {}) create_association!(attributes = {}) reload_association Giả sử ta có model như sau: class Book < ApplicationRecord ...

Phần này mình sẽ giới thiệu chi tiết về: belongs_to

  • association
  • association=(associate)
  • build_association(attributes = {})
  • create_association(attributes = {})
  • create_association!(attributes = {})
  • reload_association

Giả sử ta có model như sau:

class Book < ApplicationRecord
  belongs_to :author
end

Với mỗi instance của Book ta có các hàm sau:

author
author=
build_author
create_author
create_author!
reload_author

1.2 association

association method trả về object của model quan hệ kia. Nếu ko tìm thấy thì sẽ trả về nil.

@author = @book.author

1.3 association=(associate)

Đây là hàm để gán giá trị cho phần tử của model quan hệ.

@book.author = @author

1.4 build_association(attributes = {})

Hàm này sẽ trả về 1 phần tử mới của model quan hệ, được khởi tạo với đầy đủ các attributes, được kêt nối với model chính bằng khóa ngoài. Phần tử này mới chỉ được khởi tạo chứ chưa được lưu vào DB

@author = @book.build_author(author_number: 123,
                                  author_name: "John Doe")

1.5 create_association(attributes = {})

Giống với hàm build nhưng sẽ lưu luôn vào DB

@author = @book.create_author(author_number: 123,
                                   author_name: "John Doe")

1.6 create_association!(attributes = {})

Giống hàm create nhưng nếu lưu thất bại thì trả về ActiveRecord::RecordInvalid

1.7 reload_association

Khi ta đã gán:

@author = @book.author

mà sau đó author bị thay đổi. Nếu ta vẫn dùng @book.author thì giá thị @author không có gì khác vì đã bị cached. Do đó ta cần dùng reload

@author = @book.reload_author

2.1 autosave

class Book < ApplicationRecord
  belongs_to :author, autosave: true
end

Nếu ta set autosave bằng true, Rails sẽ lưu và load lại thành viên và xóa các thành viên bị đánh dấu xóa khi bạn lưu object cha.

2.2 class_name

Nếu class name của model kia không giống với tên của association thì ta cần sửa dụng :class_name để xác định name của model đó.

class Book < ApplicationRecord
  belongs_to :author, class_name: "Patron"
end

2.3 counter_cache

counter_cache dùng để đếm số lượng objects con của một object cha.

class Book < ApplicationRecord
  belongs_to :author, counter_cache: true
end
class Author < ApplicationRecord
  has_many :books
end

2.4 dependent

Có 2 loại:

  • dependent: :destroy khi object bị xóa, nó sẽ xóa tất cả các objects liên quan (tương tự như destroy từng objetc con).
  • dependent: :delete khi object bị xóa, thì các objects liên quan sẽ bị xóa trực tiếp trong DB mà ko qua hàm destroy Lưu ý khi sử dụng option này, vì có thể làm cho 1 số record bị mồ côi (tức là khóa ngoài có id của cha, nhưng cha đã bị xóa)

2.5 foreign_key

Khi tên của convention không giống với foreign_key trong DB thì cần khai báo foreign_key trong quan hệ

class Book < ApplicationRecord
  belongs_to :author, class_name: "Patron",
                        foreign_key: "patron_id"
end

2.6 touch

Nếu set :touch bằng true, thì khi lưu hoặc xóa object cha, object con sẽ được cập nhật updated_at hoặc updated_on vào đúng thời điểm đó

class Book < ApplicationRecord
  belongs_to :author, touch: true
end
 
class Author < ApplicationRecord
  has_many :books
end

Nếu bạn muốn chỉnh sửa query của quan hệ belongs_to, bạn có thể dùng scope: Ví dụ:

class Book < ApplicationRecord
  belongs_to :author, -> { where active: true },
                        dependent: :destroy
end

Ta có thể sử dụng các loại query methods:

  • where
  • includes
  • readonly
  • select

3.1 where

Khi sử dụng where thì ngoài điều kiện khóa ngoài thì object của model quan hệ còn phải thỏa mãn điều kiện thêm trong where.

class book < ApplicationRecord
  belongs_to :author, -> { where active: true }
end

3.2 includes

Phương thức includes sẽ lấy sẵn model đi kèm với model quan hệ để có thể sử dụng mà không cần query thêm.

class LineItem < ApplicationRecord
  belongs_to :book, -> { includes :author }
end
 
class Book < ApplicationRecord
  belongs_to :author
  has_many :line_items
end
 
class Author < ApplicationRecord
  has_many :books
end

Tuy nhiên việc này là không cần thiết vì ta có thể dùng phương thức includes ở ngoài khi query lấy ra object đấy

3.3 readonly

Nếu sử dụng readonly, thì khi các object quan hệ được lấy ra sẽ chỉ có quyền read-only

3.4 select

Sử dụng select ta có thể chỉ định các trường có thể lấy ra khi gọi ra các object quan hệ. Lưu ý: nên select foreign_key để bảo đảm kết quả được chính xác

0