12/08/2018, 17:29

Một số Options hửu ích khi tạo Association

Gĩa sử mình có 2 model Author và Book. khi mình gọi @author.books.size rails sẻ truy cấn database để thực thi câu lệnh count(). Để tránh cuộc gọi này mình có thể thêm tùy chọn counter_cache khi định nghĩa liên kết belong_to class Book < ApplicationRecord belongs_to :author, counter_cache: ...

Gĩa sử mình có 2 model Author và Book. khi mình gọi @author.books.size rails sẻ truy cấn database để thực thi câu lệnh count(). Để tránh cuộc gọi này mình có thể thêm tùy chọn counter_cache khi định nghĩa liên kết belong_to

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

Lưu ý mình cần thêm cột books_count trong table author Lúc này mỗi khi mình tạo thêm hoặc xóa book thì giá trị của cột books_count của author tương ứng sẽ được cập nhật. khi cần đếm số book của một author ta chỉ @author.books_count mà không cần thực hiện một query nào

Để hiểu rỏ hơn về sự hửu ích của tùy chọn này mình cần tìm hiểu Bi-directional Associations trước

Bi-directional Associations

Active Record tự động xác định 2 mô hình này có liên kết 2 chiều. Điều này có nghĩa Active Record sẽ chỉ tải một bản sao của đối tượng author. Làm cho ứng dụng của mình hiệu quả hơn, ngăn ngừa dữ liệu không nhất quán. Ví dụ:

a = Author.first
b = a.books.first
a.first_name == b.author.first_name # => true
a.first_name = 'David'
a.first_name == b.author.first_name # => true

Khi liên kết có chứa các tùy chọn sau thì active record không thể tự động xác định bi-directional associations cho liên kết: :conditions :through :polymorphic :class_name :foreign_key

class Author < ApplicationRecord
  has_many :books
end
 
class Book < ApplicationRecord
  belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'
end

Kết quả

a = Author.first
b = a.books.first
a.first_name == b.writer.first_name # => true
a.first_name = 'David'
a.first_name == b.writer.first_name # => false

Và inverse_of chính là tùy chọn để mình khai báo bi-directional associations một các rõ ràng

class Author < ApplicationRecord
  has_many :books, inverse_of: 'writer'
end
 
class Book < ApplicationRecord
  belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'
end

Kết quả

a = Author.first
b = a.books.first
a.first_name == b.author.first_name # => true
a.first_name = 'David'
a.first_name == b.author.first_name # => true

Một số gới hạn của tùy chọn này là không thực hiện được khi liên kết có các tùy chọn như: through, polymorphic, as

Như các callback thông thường, nó sẻ hook vào vòng đời của các đối tượng, cho phép mình làm việc với đối tượng ở nhiều giai đoạn khác nhau. Ví dụ: before_save callback sẻ hook vào trước khi đối tượng được lưu Tương tự association callbacks sẽ hook vào vòng đợi của một collection. Có 4 association callbacks:

before_add after_add before_remove after_remove

Bằng cách thêm các tùy chọn này vào lúc khai báo liên kết. Ví dụ:

class Author < ApplicationRecord
  has_many :books, before_add: :check_credit_limit
 
  def check_credit_limit(book)
    ...
  end
end

Bạn có thể tìm hiểu thêm tại đây http://guides.rubyonrails.org/association_basics.htm

0