12/08/2018, 15:17

Option in association :source, :as and :source_type. Những điều thú vị về association. Có thể bạn đã biết

[ Có thể bạn đã biết] Nói đến association chắc hẳn các bạn đều đã biết. Bài viết của mình chỉ nêu nhưng khái niệm cơ bản mà mình tìm hiểu và tóm tắt đc trong quá trình training nên nếu có gì sai xót mong được góp ý để sửa đổi ạ. Mình sẽ nói về các OPTIONS trong quan hệ của rails mà mình biết. ...

[ Có thể bạn đã biết] Nói đến association chắc hẳn các bạn đều đã biết. Bài viết của mình chỉ nêu nhưng khái niệm cơ bản mà mình tìm hiểu và tóm tắt đc trong quá trình training nên nếu có gì sai xót mong được góp ý để sửa đổi ạ.

Mình sẽ nói về các OPTIONS trong quan hệ của rails mà mình biết.

1. :Option của association belongs_to

  • Giả sử ta có quan hệ users 1 - n books
#model users
  has_many :books, dependent: :destroy

#model books
  belongs_to :user

#migrate book
  t.integer :user_id

1.1 class_name

Với association này thì bạn có thể gọi user của 1 book ví dụ: Book.first.user

=> Nhưng nếu trong migrate book bạn không đặt là user_id (vì mặc định Rails sẽ nhận trong association là tên_model_id là khóa ) mà bạn đặt là owner_id liên kết với model User thì sao. thì option classname và foreign_key sẽ cứu cánh cho bạn

#model books
  belongs_to owner, class_name: User.name, foreign_key: :owner_id

#class_name sẽ nói cho Rails biết bạn sẽ belongs_to đến model nào.
#foreign_key sẽ nói cho Rails biết bạn sẽ belongs_to đến model theo key nào.

1.2 counter_cache

Theo mình được biết. option này sẽ hỗ trợ mình tìm kiếm số lượng bản ghi hiệu quả hơn.

  • Điều kiện.
# trong file migrate của users
  t.integer :books_count

ví dụ @user.books.size trả về số lượng book của user sẽ gọi đến database môt query COUNT(*). Bạn có thể thay thế nó bằng một option thú vị sau

#model users
  has_many :books
#model books
  belongs_to :user, counter_cache: true

# Ngoai ra bạn có thể overide trường books_count mặc định Rails hiểu thành tên một trường khác chẳng hạn như books_of_count
  belongs_to :user, counter_cache: :books_of_count

1.3 primary_key

Mặc định Rails hiểu column id là khóa chính của một bảng. Nhưng giờ bạn muốn khóa chính là một trường khác thì :primary_key option sẽ thực hiện được việc này. Giả sử table users có trường 'guid' là khóa chính.

#model user
  self.primary_key = 'guid'

#model book
  belongs_to :user,  primary_key: 'guid' 

Thì khi bạn gọi @user.books.create thì bản ghi của book sẽ nhận user_id là giá trị 'guid' của @user

1.4 :optional

Trong rails 5. mặc định option này có giá trị bằng false. Thì model belongs_to sẽ yêu cầu validate với model has_many nó. ví dụ: book belongs_to user thì khi bạn tạo book rails sẽ yêu cầu bạn phải có user. nếu bạn đặt optional: true thì validate sẽ bị vô hiệu.

Ngoài ra còn một số option khác mình chưa đề cập. Bạn có thể tham khảo link cuối trang nhé.

2. Option :source, :as, :source_type trong has_many or has_one

2.1 :source.

Đây là thuộc tính xác định tên liên kết nguồn cho liên kết hasmany through. Khi nào mà tên của association nguồn không thể tự động sinh ra thì source sẽ là cần thiết.

Ví dụ: ta có 3 model

  • pet 1-n dog
  • dog 1-n voi breed Vậy làm sao để lấy tất cả breed với @pet
# model Pet
  has_many :dogs
# model Dog
  belongs_to :pet
  has_many :breeds
# model Breed
  belongs_to :dog

giờ chúng ta tạo một association has_many :dog_breeds trong model Pet thì sao nhỉ.

Nếu không dùng source thì sao. bạn hãy thử xem.

# model Pet
  has_many :dog_breeds, through: :dogs

Rails sẽ không tìm thấy association dog_breeds trong model Dog.

Phương án đề ra

# model Pet
  has_many :dog_breeds, through: :dogs, source: :breeds

Chúng ta nói cho Rails biết rằng. pet gọi dogbreeds thông qua breeds trong model Dog

2.2 :source_type

source_type được sử dụng khi bạn sử dụng với model polymorphic Mình có ví dụ sau: Hơi khó hiểu tý xíu :p

Book và Movie quan hệ nhiều nhiều với Tag => thông qua 2 bảng trung gian là book_tags và movie_tag nhưng chúng ta sẽ sử dụng tagging để polymorphic đến book và movie

  • tag 1-n tagging
  • book and movie n-n với tag through qua tagging
  • tagging polymorphic với book và movie

Như association dưới thì để @tag.books thì chúng ta phải through qua associaton taggings của model Tag, nhưng trong taggings lại KHÔNG có association* belongsto book* => phải option source: taggable, nhưng làm sao Tagging biết được gọi đến* model Book vì đang** polymorphic cơ mừ***. => option sourcetype: Book.name để Rails hiểu là gọi đến Book

class Tag < ActiveRecord::Base
  has_many :taggings, :dependent => :destroy
  has_many :books, :through => :taggings, :source => :taggable, :source_type => "Book"     #hoặc Book.name đều được
  has_many :movies, :through => :taggings, :source => :taggable, :source_type => "Movie" #hoặc Movie.name đều được
end

class Tagging < ActiveRecord::Base
  belongs_to :taggable, :polymorphic => true
  belongs_to :tag
end

class Book < ActiveRecord::Base
  has_many :taggings, :as => :taggable
  has_many :tags, :through => :taggings
end

class Movie < ActiveRecord::Base
  has_many :taggings, :as => :taggable
  has_many :tags, :through => :taggings
end

2.3 as

Như các bạn thấy association ở 2.2 trong model Book và Tagging. có sử dụng option as: :taggle . Thì option :as là được sử dụng trong association polymorphic.

 class Tagging < ActiveRecord::Base
  belongs_to :taggable, :polymorphic => true
end

class Book < ActiveRecord::Base
  has_many :taggings, :as => :taggable
end

@book.taggings Bình thường bạn chỉ cần hasmany :taggings là ĐỦ nhưng vì tagging đang là polymorphic thông qua taggble nên ta phải nói cho Rails biết là** "Tao muốn lấy tagging mà có taggable là Book"**

Còn rất nhiều các option khác mà mình vẫn chưa tìm hiểu hết được nên mình chỉ nêu được những cái mình hiểu ở đâ. Các option này tuy đơn giản nhưng khi vào thực tế bạn thường nhầm lẫn chúng với nhau nên các bạn nên đọc các tài liệu khác để hiểu rõ hơn. Có gì sai xót mong mọi người góp ý. Xin chân thành cảm ơn!

Bạn đọc đến đây thì bạn cũng chăm chỉ đó. Moa moa

Link nè: http://guides.rubyonrails.org/association_basics.html Toàn tiếng anh mẹ không à.

0