How to Use Scopes in Ruby on Rails
Scope trong Ruby là gì? Tại sao chúng ta nên sử dụng nó? Scope là việc bận custom các câu truy vấn, được định nghĩa trong các model của Rails với method scope. Mỗi scope có 2 tham số: Một tên(name), cái mà bạn sẽ gọi nó trong code khi cần sử dụng scope Một lambda, để thực thi câu truy vấn ...
Scope trong Ruby là gì? Tại sao chúng ta nên sử dụng nó?
Scope là việc bận custom các câu truy vấn, được định nghĩa trong các model của Rails với method scope.
Mỗi scope có 2 tham số:
- Một tên(name), cái mà bạn sẽ gọi nó trong code khi cần sử dụng scope
- Một lambda, để thực thi câu truy vấn
Ví dụ:
class Fruit < ApplicationRecord scope :with_juice, -> { where("juice > 0") } end
Kết quả của việc gọi scope này là một đối tượng ActiveRecord::Relation. Điều này có nghĩa rằng bạn có thể gọi các scope liên tiếp nhau. Ví dụ:
Fruit.with_juice.with_round_shape.first(3)
Hãy cùng xem ví dụ:
def index @books = Book.where("LENGTH(title) > 20") end
Đây là đoạn code trong action index của controller, để hiển thị danh sách các quyển sách có độ dài tiêu đề lớn hơn 20 kí tự.
Nhưng nếu bạn muốn sử dụng câu truy vấn này ở một nơi khác, bạn sẽ bị dupplicate code. Dupplicate code dẫn đến dự án rất khó để maintain. Hãy cùng nhau chuyển câu truy vấn này vào trong scope.
Như sau:
class Book scope :with_long_title, -> { where("LENGTH(title) > 20") } end
Bây giờ, trong controller chỉ việc gọi:
def index @books = Book.with_long_title end
Có những trường hợp, bạn muốn truyền biến vào trong một scope để làm cho scope trở nên linh hoạt hơn:
class Book scope :with_long_title, ->(length) { where("LENGTH(title) > ?", length) } end
Nếu bạn muốn có một giá trị default cho tham số:
class Book scope :with_long_title, ->(length = 20) { where("LENGTH(title) > ?", length) } end
Scope cũng có những giới hạn của nó, nó không phải là chìa khóa vạn năng có thể giải quyết được nhiều vấn đề, bởi đơn giản, chúng chỉ là những method. Trên thực tế, bạn có thể làm những việc tương tự scope bằng cách sử dụng class method.
class Fruit def self.with_juice where("juice > 0") end end
Nhưng có nhiều lợi ích của việc sử dụng scope hơn là các class method:
- Scope làm code clean hơn bởi chính cú pháp của chúng.
- Scope thực hiện duy nhất một điều gì đó, nên khi đọc code bạn dễ dàng nắm bắt được đang làm vấn đề gì
- Scope không trộn lẫn được với những method khác nên chúng dễ dàng được nhận ra
Về chức năng, thì scope chỉ có một khác biệt duy nhất với class method, là scope luôn đảm bảo kết quả trả về là một ActiveRecord::Relation, còn class method thì không.
Một default scope là một scope sẽ được tự động thực hiện trong model của bạn. Ví dụ:
class Post default_scope { where(published: true) } end
Default scope trông khá thú vị, nhưng không nên sử dụng chúng, bởi vì bạn có thể quên rằng chúng tồn tại, gây ra các lỗi tiềm ẩn, và mất thời gian để điều tra các lỗi phát sinh. Nếu bạn phải làm việc với default scope, có thể bạn sẽ cần sử dụng method unscoped để disable tất cả các scope đã apply hiện tại.
Source:
https://www.rubyguides.com/2019/10/scopes-in-ruby-on-rails/?tl_inbound=1&tl_target_all=1&tl_period_type=1