10 ActiveRecord::Relation Methods ít được sử dụng trong Rails
10. first_or_create first_or_create thì khá là quen thuộc rồi: Book . where ( :title = > 'Tale of Two Cities' ) . first_or_create và chỉ nghe tên là bạn đủ hiểu nó sẽ làm gì. Cụ thể, bạn sẽ muốn tìm một record với các thuộc tính cho trước, nếu không tìm thấy, tạo một ...
10. first_or_create
first_or_create thì khá là quen thuộc rồi:
Book.where(:title => 'Tale of Two Cities').first_or_create
và chỉ nghe tên là bạn đủ hiểu nó sẽ làm gì. Cụ thể, bạn sẽ muốn tìm một record với các thuộc tính cho trước, nếu không tìm thấy, tạo một record chứa các thuộc tính đó, và có thể thêm một vài thuộc tính khác. Để làm được điều này, rất đơn giản, bạn thêm block cho first_or_create:
Book.where(:title => 'Tale of Two Cities').first_or_create do |book| book.author = 'Charles Dickens' book.published_year = 1859 end
9. first_or_initialize
Nếu bạn chưa muốn save vào DB ngay, có thể dùng first_or_initialize
Book.where(:title => 'Tale of Two Cities').first_or_initialize
8. scoped
Khi bạn muốn ActiveRecord::Relation trả về toàn bộ records của class, có thể dùng scoped. Từ Rails v3.1.0 thì method này đã bị xóa bỏ.
def search(query) if query.blank? scoped else q = "%#{query}%" where("title like ? or author like ?", q, q) end end
7. none (Rails 4 only)
Có những lúc bạn muốn kêt quả trả về là một ActiveRecord::Relation không chứa một object nào cả. Nếu trả về một mảng rỗng hoặc một "cái gì đó" rỗng thì không phải là ý hay khi khách hàng của bạn muốn một relation object. Khi đó ta dùng none:
def filter(filter_name) case filter_name when :all scoped when :published where(:published => true) when :unpublished where(:published => false) else none end end
Note: Bạn rất nên cẩn thận khi dùng none. Rails 4 đã hỗ trợ, còn Rails 3 thì không.
6. find_each
Khi bạn cần chạy lặp qua cả ngàn records, chắc bạn sẽ không muốn dùng each. Nghĩa là chỉ cần query 1 lần, cả ngàn records sẽ chui sẵn vào bộ nhớ. Nếu bạn có thừa thãi bộ nhớ, cứ việc làm như trên. Ngược lại, việc này sẽ có thể làm treo app của bạn bất cứ lúc nào. find_each sẽ chỉ query lần lượt một số records nhất định trong một thời điểm (mặc định là 1000), cho nên bạn sẽ không tốn bộ nhớ khi bạn có quá nhiều dữ liệu.
Book.where(:published => true).find_each do |book| puts "Do something with #{book.title} here!" end
5. to_sql and explain
ActiveRecord thật sự rất ngon, nhưng đôi khi nó trả ra những kết quả mà bạn không hề mong muốn. Chạy những lệnh trên trong khi debug hoặc trong rails console, để xem câu query mà bạn dựng bằng Rails có chuẩn xác hay không.
Library.joins(:book).to_sql # => SQL query for you database. Libray.joins(:book).explain # => Database explain for the query.
4. find_by
Bạn có một câu dài dòng kiểu như:
Book.where(:title => 'Three Day Road', :author => 'Joseph Boyden').first
Thay vào đó, bạn có thể sử dụng find_by:
Book.find_by(:title => 'Three Day Road', :author => 'Joseph Boyden')
cũng cho kết quả y hệt!
Note: Thật cẩn thận khi dùng find_by, chỉ Rails 4 trở lên mới hỗ trợ, Rails 3 thì không.
3. scoping
Bạn có thể viết lại 1 class method riêng cho 1 trường hợp nào đó giống như scope với models. Tham khảo ví dụ dưới đây được lấy từ tài liệu của Rails:
Comment.where(:post_id => 1).scoping do Comment.first # SELECT * FROM comments WHERE post_id = 1 end
2. pluck
Khi muốn đưa ra array giá trị 1 cột của các records, thông thường ta hay sử dụng
published_book_titles = Book.published.select(:title).map(&:title)
hay là
published_book_titles = Book.published.map(&:title)
thì ta có thể dùng pluck để thay thế
published_book_titles = Book.published.pluck(:title) # => ["Norwegian Wood", "The Catcher in the Rye", ...]
1. merge
Đây là 1 method rất hữu dụng khi sử dụng trong ActiveRecord::Relation. Bạn có thể vừa joins bảng vừa lọc với 1 scope nào đó trong models
class Account < ActiveRecord::Base # Returns all the accounts that have unread messages. def self.with_unread_messages joins(:messages).merge( Message.unread ) end end
Bài viết được dịch từ The 10 Most Underused ActiveRecord::Relation Methods