Một vài vấn đề về Active Record Associations (phần 3)
Phần này chúng ta sẽ tìm hiểu chi tiết về: has_many Khi ta khai báo một has_many association, sẽ có 17 hàm liên quan đến association này: collection collection<<(object, ...) collection.delete(object, ...) collection.destroy(object, ...) collection=(objects) collection_singular_ids colle ...
Phần này chúng ta sẽ tìm hiểu chi tiết về: has_many
Khi ta khai báo một has_many association, sẽ có 17 hàm liên quan đến association này:
collection collection<<(object, ...) collection.delete(object, ...) collection.destroy(object, ...) collection=(objects) collection_singular_ids collection_singular_ids=(ids) collection.clear collection.empty? collection.size collection.find(...) collection.where(...) collection.exists?(...) collection.build(attributes = {}, ...) collection.create(attributes = {}) collection.create!(attributes = {}) collection.reload
Trong tất cả các hàm, collection sẽ được thay thế bởi ký hiệu của đối tượng đầu tiên trọng quan hệ has_many (ở dạng số nhiều), còn collection_singular thì là đối tượng đó nhwung ở dạng số ít. Ví dụ: Ta có 2 model Author và Book có quan hệ như sau:
class Author < ApplicationRecord has_many :books end
Với mỗi Author ta có các hàm sau:
books books<<(object, ...) books.delete(object, ...) books.destroy(object, ...) books=(objects) book_ids book_ids=(ids) books.clear books.empty? books.size books.find(...) books.where(...) books.exists?(...) books.build(attributes = {}, ...) books.create(attributes = {}) books.create!(attributes = {}) books.reload
Dưới đây ta đi chi tiết vào 1 số hàm:
1.1 collection
Hàm collection trả về tất cả các objects con. Nếu không có object nào thì sẽ trả về rỗng.
@books = @author.books
1.2 collection<<(object, ...)
Hàm collection<< để thêm 1 hoặc nhiều objects con vào quan hệ với object cha.
@author.books << @book1
1.3 collection.delete(object, ...)
Hàm collection.delete sẽ loại bỏ 1 hoặc nhiều objects con ra khỏi quan hệ với object cha bằng cách xét khóa ngoài của nó thành NULL.
@author.books.delete(@book1)
1.4 collection_singular_ids
Hàm này trả về mảng các id của các objects con.
@book_ids = @author.book_ids
1.5 collection.empty?
Hàm này trả về true nếu không có object con nào tồn tại thỏa mãn quan hệ với object cha.
<% if @author.books.empty? %> No Books Found <% end %>
1.6 collection.size
Hàm này trả về số lượng object con.
@book_count = @author.books.size
1.7 collection.build(attributes = {}, ...) và collection.create(attributes = {})
Hàm này để tạo 1 hoặc nhiều object con từ object cha, có sẵn khóa ngoài là khoá chính của object cha.
@book = @author.books.build(published_at: Time.now, book_number: "A12345") @books = @author.books.build([ { published_at: Time.now, book_number: "A12346" }, { published_at: Time.now, book_number: "A12347" } ]) @book = @author.books.create(published_at: Time.now, book_number: "A12345") @books = @author.books.create([ { published_at: Time.now, book_number: "A12346" }, { published_at: Time.now, book_number: "A12347" } ])
1.8 collection.reload
Hàm này vẫn trả về toàn bộ objects con trong quan hệ, nhưng gọi lại từ database để đảm bảo được dữ liệu mới nhất của các object con.
@books = @author.books.reload
has_many hỗ trợ các options sau:
:as :autosave :class_name :counter_cache :dependent :foreign_key :inverse_of :primary_key :source :source_type :through :validate
Dưới đây ta tìm hiểu 1 vài options chính:
2.1 :autosave
Nếu ta xét autosave là true, thì bất cứ khi nào ta save object cha, các objects con cũng sẽ được save hoặc xóa nếu bị đánh dấu xóa. Việc xét autosave là false khác với việc không xét autosave. Nếu ta không xét autosave thì khi ta tạo mới object cha cùng object con thì cả 2 sẽ cùng được save, còn khi ta update object cha, object con sẽ không được save.
2.2 :class_name
Nếu tên của model cha mà không trùng với tên quan hệ mình muốn đặt thì ta cần thêm option class_name để chỉ chính xác tên model.
class Author < ApplicationRecord has_many :books, class_name: "Transaction" end
2.3 :dependent
Đây là option để xử lý các objects con khi mà object cha bị xóa, có các lựa chọn sau:
- :destroy: các object con sẽ bị xóa cùng cha.
- :delete_all: các object con sẽ bị xóa trực tiếp từ database.
- :nullify: khóa ngoài của các object con được xét thành NULL.
2.4 :foreign_key
Nếu tên của khóa ngoài không trùng với model cha thì cần thêm option foreign_key.
class Author < ApplicationRecord has_many :books, foreign_key: "cust_id" end
2.5 :validate
Nếu xét :validate là false, thì khi save object cha, không cần kiểm tra validate của các objects con. Mặc định thì option :validate được xét là true.
Ta có các scopes sau:
where extending group includes limit offset order readonly select distinct
3.1 where
Hàm where để xác định thêm điều kiện lọc ra các objects con.
class Author < ApplicationRecord has_many :confirmed_books, -> { where "confirmed = 1" }, class_name: "Book" end
Có thể viết dưới dạng hash:
class Author < ApplicationRecord has_many :confirmed_books, -> { where confirmed: true }, class_name: "Book" end
Nếu ta viết dạng hash thì khi tạo objects con từ object cha, điều kiện đi cùng hàm where sẽ được áp dụng kèm luôn. Với vị dụ về Author và Book ở trên, nếu ta sử dụng @author.confirmed_books.create hoặc @author.confirmed_books.build để tạo books thì cột confirmed sẽ có sẵn giá trị là true.
3.2 group
Hàm này cần tên 1 trường để nhóm các kết quả lại, nó sử dụng hàm GROUP BY của SQL.
class Author < ApplicationRecord has_many :line_items, -> { group 'books.id' }, through: :books end
3.3 includes
Hàm includes cho phép ta sử dụng luôn eager-loaded khi gọi 1 quan hệ.
class Author < ApplicationRecord has_many :books, -> { includes :line_items } end class Book < ApplicationRecord belongs_to :author has_many :line_items end class LineItem < ApplicationRecord belongs_to :book end
Lúc này ta gọi @author.books.line_items thì lượng query sẽ được tối giản.
3.4 limit
Hàm limit cho phép hạn chế số lượng objects con.
class Author < ApplicationRecord has_many :recent_books, -> { order('published_at desc').limit(100) }, class_name: "Book" end
3.5 order
Các objects con sẽ được sắp xếp theo 1 trường nào đấy khi được gọi thông qua quan hệ. Sử dụng lệnh ORDER BY của SQL.
class Author < ApplicationRecord has_many :books, -> { order "date_confirmed DESC" } end
3.6 select
Ta có thể chỉ định trả về các trường nhất định của objects con. Mặc định sẽ trả về hết tất cả các trường.
http://guides.rubyonrails.org/association_basics.html#options-for-has-many-autosave