ActiveRecord là một trong những "vũ khí bí mật" của Rails, giúp chúng ta thao tác với cơ sở dữ liệu một cách dễ hiểu và gọn gàng. Tuy nhiên, nhiều developer chưa tận dụng hết sức mạnh của nó. Bài viết này chia sẻ những mẹo giúp viết truy vấn ActiveRecord hiệu quả hơn.
1. Dùng pluck
thay vì map
Khi chỉ cần lấy một vài trường dữ liệu, pluck
nhanh và tiết kiệm tài nguyên hơn so với map
:
# BAD
User.where(active: true).map(&:email) # Good
User.where(active: true).pluck(:email)
👉 pluck chỉ trả về mảng giá trị, không tạo object ActiveRecord.
2. Dùng select để giảm tải dữ liệu
Không phải lúc nào cũng cần load toàn bộ cột của một bản ghi, khi chỉ cần lấy một vài cột của bản ghi chúng ta nên sử dụng select:
User.select(:id, :name).where(active: true)
👉 Kết hợp tốt với readonly nếu không muốn ghi đè dữ liệu.
3. Truy vấn liên kết bằng joins hoặc includes
Khi cần lọc dữ liệu liên quan, joins là lựa chọn tốt:
Post.joins(:category).where(categories: { name: 'Tech' })
👉 Dùng joins để filter, includes để load dữ liệu liên quan (tránh N+1).
4. Chain query giúp code rõ ràng hơn
ActiveRecord cho phép chain nhiều truy vấn lại với nhau:
User.active.order(:created_at).limit(10)
👉 Có thể viết scope để tái sử dụng dễ dàng hơn
5. Dùng merge khi kết hợp nhiều scope từ model khác
Khi join bảng khác và muốn áp dụng scope của nó:
# Trong Post model
scope :published, -> { where(published: true) } # Trong User
User.joins(:posts).merge(Post.published)
👉 merge giúp tái sử dụng logic truy vấn một cách chuẩn REST.
6. Tận dụng scope trong model
Viết scope trong model giúp tái sử dụng và dễ test hơn:
# app/models/user.rb
scope :active, -> { where(active: true) }
scope :recent, -> { order(created_at: :desc) } # Sử dụng
User.active.recent.limit(5)
👉 Mỗi scope nên làm một việc và có thể chain lại được.
7. Tìm bản ghi duy nhất nhanh gọn
# Tìm theo id
User.find(1) # Tìm theo điều kiện
User.find_by(email: 'abc@example.com') # Hoặc raise lỗi nếu không tìm thấy
User.find_by!(email: 'abc@example.com')
👉 find_by! rất hữu ích để fail fast trong logic quan trọng.
8. Sử dụng group, having, distinct khi cần tổng hợp
# Đếm số bài viết theo user
Post.group(:user_id).count # Lấy user đã đăng hơn 10 bài
Post.group(:user_id).having('COUNT(*) > 10').count # Tránh trùng lặp
User.select(:email).distinct
9. Khi cần custom SQL, cứ dùng .where với string
User.where("created_at >= ?", 7.days.ago)
👉 Đừng lạm dụng raw SQL, nhưng cũng đừng ngại dùng khi cần tối ưu.
Kết luận
Viết truy vấn ActiveRecord hiệu quả không chỉ giúp code sạch hơn mà còn giúp ứng dụng nhanh hơn đáng kể. Hãy chọn đúng công cụ cho đúng trường hợp, và luôn nghĩ đến hiệu suất khi làm việc với dữ liệu lớn.
Bạn có thói quen viết query ActiveRecord thế nào? Hãy chia sẻ thêm mẹo của bạn nhé!