Option in association :source, :as and :source_type. Những điều thú vị về association. Có thể bạn đã biết
Bài đăng này đã không được cập nhật trong 7 năm
[ 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 à.
All rights reserved