Rails nội bộ chuyển đổi phạm vi thành các phương thức lớp, vậy tại sao chúng ta không thể sử dụng các phương thức lớp thay vì đi theo phạm vi.Ruby on Rails Phạm vi ActiveRecord vs các phương thức lớp
Trả lời
Từ fine guide:
14 Scopes
[...]
Để xác định một phạm vi đơn giản, chúng tôi sử dụng phương phápscope
bên trong lớp, đi qua các truy vấn mà chúng tôi muốn để chạy khi phạm vi này được gọi là:class Article < ActiveRecord::Base scope :published, -> { where(published: true) } end
Điều này cũng giống như xác định phương pháp lớp học và bạn sử dụng phương pháp này là vấn đề của con người al ưu tiên:
class Article < ActiveRecord::Base def self.published where(published: true) end end
Lưu ý đặc biệt:
Đây là chính xác giống như xác định một phương pháp học, và mà bạn sử dụng là một vấn đề sở thích cá nhân
Và a little further (hướng dẫn Rails3 nói cùng một điều ở đây BTW):
14.1 Truyền tham số
[...]
Sử dụng phương thức lớp là cách ưu tiên để chấp nhận đối số cho phạm vi.
Vì vậy, bạn sử dụng nó là vấn đề ưu tiên và thậm chí bạn nên sử dụng phương pháp lớp cho phạm vi lấy đối số.
Sử dụng scope
chủ yếu là vấn đề không hợp lý. Nếu bạn nói scope :whatever
thì bạn đang nói rõ ràng rằng whatever
là một trình tạo truy vấn; nếu bạn nói def self.whatever
thì bạn không ngụ ý bất cứ điều gì về mục đích của phương pháp whatever
, bạn chỉ định nghĩa một số phương thức lớp có thể hoặc có thể không hoạt động như một phạm vi.
Tất nhiên, 14.1 làm cho một mớ hỗn độn của sự phân biệt này bằng cách đề xuất bạn không sử dụng scope
khi phạm vi của bạn có đối số. Cũng nên nhớ rằng trong Rails3 bạn có thể nói:
scope :published, where(published: true)
vì vậy một phạm vi argumentless là trực quan "sạch" và ngắn gọn nhưng thêm một lambda để xử lý đối số sẽ làm cho nó trông Messier:
scope :pancakes, ->(x) { where(things: x) }
Nhưng Rails4 muốn lambdas ngay cả đối với phạm vi tranh luận sự khác biệt thậm chí còn ít ý nghĩa hơn bây giờ.
Tôi nghi ngờ rằng sự khác biệt là lịch sử tại thời điểm này. Phạm vi có lẽ là một cái gì đó đặc biệt trở lại trong thời gian trước nhưng trở thành phương pháp cũ lớp đồng bằng trong thời đại Rails3 để cắt giảm trên sao chép và lưới tốt hơn với giao diện truy vấn mới đi kèm với Rails3.
Vì vậy, bạn có thể bỏ qua scope
và chuyển thẳng đến các phương thức lớp học nếu muốn. Bạn thậm chí còn được khuyến khích làm như vậy khi phạm vi của bạn có lý lẽ.
Tại sao tôi nên sử dụng phạm vi nếu đó chỉ là đường cú pháp cho phương pháp lớp? ". Đây là một số ví dụ thú vị để bạn suy nghĩ.
Phạm vi luôn có thể chuỗi => •••••••••••••••••••••••••••••••••••••••••••••••• ••••• Cho phép sử dụng kịch bản sau: người dùng sẽ có thể lọc bài đăng theo trạng thái, sắp xếp theo các cập nhật gần đây nhất. Đủ đơn giản, cho phép viết phạm vi cho điều đó:
class Post < ActiveRecord::Base
scope :by_status, -> status { where(status: status) }
scope :recent, -> { order("posts.updated_at DESC") }
end
And we can call them freely like this:
Post.by_status('published').recent
# SELECT "posts".* FROM "posts" WHERE "posts"."status" = 'published'
# ORDER BY posts.updated_at DESC
Or with a user provided param:
Post.by_status(params[:status]).recent
# SELECT "posts".* FROM "posts" WHERE "posts"."status" = 'published'
# ORDER BY posts.updated_at DESC
So far, so good. Now lets move them to class methods, just for the sake of comparing:
class Post < ActiveRecord::Base
def self.by_status(status)
where(status: status)
end
def self.recent
order("posts.updated_at DESC")
end
end
Ngoài việc sử dụng thêm một vài dòng, không có cải tiến lớn. Nhưng bây giờ điều gì sẽ xảy ra nếu thông số trạng thái: là nil hoặc trống?
Post.by_status(nil).recent
# SELECT "posts".* FROM "posts" WHERE "posts"."status" IS NULL
# ORDER BY posts.updated_at DESC
Post.by_status('').recent
# SELECT "posts".* FROM "posts" WHERE "posts"."status" = ''
# ORDER BY posts.updated_at DESC
Oooops, I don't think we wanted to allow these queries, did we? With scopes, we can easily fix that by adding a presence condition to our scope:
scope :by_status, -> status { where(status: status) if status.present? }
There we go:
Post.by_status(nil).recent
# SELECT "posts".* FROM "posts" ORDER BY posts.updated_at DESC
Post.by_status('').recent
# SELECT "posts".* FROM "posts" ORDER BY posts.updated_at DESC
Awesome. Now lets try to do the same with our beloved class method:
class Post < ActiveRecord::Base
def self.by_status(status)
where(status: status) if status.present?
end
end
Running this:
Post.by_status('').recent
NoMethodError: undefined method `recent' for nil:NilClass
And . The difference is that a scope will always return a relation, whereas our simple class method implementation will not. The class method should look like this instead:
def self.by_status(status)
if status.present?
where(status: status)
else
all
end
end
Lưu ý rằng tôi trả về tất cả cho trường hợp nil/trống, trong đó Rails 4 trả về một mối quan hệ (trước đó nó trả về mảng các mục từ cơ sở dữ liệu). Trong Rails 3.2.x, bạn nên sử dụng scoped ở đó để thay thế. Và đó chúng tôi đi:
Post.by_status('').recent
# SELECT "posts".* FROM "posts" ORDER BY posts.updated_at DESC
Vì vậy, lời khuyên ở đây là: không bao giờ quay trở lại con số không từ một phương pháp học mà nên làm việc như một phạm vi, nếu không bạn đang phá vỡ tình trạng chainability ngụ ý bởi phạm vi, mà luôn luôn trả về một mối quan hệ.
Phạm vi có thể mở rộng => •••••••••••••••••••••••••••••••••••••••• Cho phép phân trang như ví dụ tiếp theo của chúng tôi và tôi ' m sẽ sử dụng đá quý kaminari làm cơ sở. Điều quan trọng nhất bạn cần làm khi paginating một bộ sưu tập là để cho các trang web mà bạn muốn lấy:
Post.page(2)
After doing that you might want to say how many records per page you want:
Post.page(2).per(15)
And you may to know the total number of pages, or whether you are in the first or last page:
posts = Post.page(2)
posts.total_pages # => 2
posts.first_page? # => false
posts.last_page? # => true
bài này có ý nghĩa khi chúng ta gọi là những thứ theo thứ tự này, nhưng nó không thực hiện bất kỳ ý nghĩa để gọi những phương thức này trong một bộ sưu tập không được phân trang, phải không? Khi bạn viết phạm vi, bạn có thể thêm các tiện ích mở rộng cụ thể sẽ chỉ khả dụng trong đối tượng của bạn nếu phạm vi đó được gọi. Trong trường hợp của kaminari, nó chỉ thêm phạm vi trang vào các mô hình Active Record của bạn và dựa vào tính năng mở rộng phạm vi để thêm tất cả các chức năng khác khi trang được gọi. Về mặt khái niệm, mã sẽ trông giống như sau:
scope :page, -> num { # some limit + offset logic here for pagination } do
def per(num)
# more logic here
end
def total_pages
# some more here
end
def first_page?
# and a bit more
end
def last_page?
# and so on
end
end
Phạm vi mở rộng là một kỹ thuật mạnh mẽ và linh hoạt trong chuỗi công cụ của chúng tôi. Nhưng tất nhiên, chúng tôi luôn luôn có thể đi hoang dã và nhận được tất cả những gì với các phương pháp lớp quá:
def self.page(num)
scope = # some limit + offset logic here for pagination
scope.extend PaginationExtensions
scope
end
module PaginationExtensions
def per(num)
# more logic here
end
def total_pages
# some more here
end
def first_page?
# and a bit more
end
def last_page?
# and so on
end
end
Đó là tiết hơn một chút so với sử dụng một phạm vi, nhưng nó mang lại kết quả tương tự. Và lời khuyên ở đây là: chọn những gì làm việc tốt hơn cho bạn nhưng hãy chắc chắn rằng bạn biết những gì khuôn khổ cung cấp trước khi phát minh lại bánh xe.
Tính đạo văn rõ ràng của http: //blog.plataformatec.com.br/2013/02/active-record-scopes-vs-class-methods/ – aceofbassgreg
- 1. Phạm vi trống với Ruby on Rails
- 2. Marshalling vs ActiveRecord Serialization trong Ruby On Rails
- 3. Ruby on Rails link_to Với phương thức
- 4. Ruby vs Ruby On Rails
- 5. Ruby on Rails ActiveRecord: số nhiều
- 6. Phương thức lớp vs hằng số trong Ruby/Rails
- 7. Phương thức hủy diệt ActiveRecord trả về giá trị boolean trong Ruby on Rails?
- 8. Ruby on Rails vs Django
- 9. Phạm vi so với Phương pháp Lớp trong Rails 3
- 10. Rails first_or_create Phương thức ActiveRecord
- 11. Nhóm PostgreSQL thanh lịch cho Ruby on Rails/ActiveRecord
- 12. Phương thức riêng tư của Ruby on Rails?
- 13. Phương thức 'on_sym' của Ruby on Rails làm gì?
- 14. Ruby on Rails: tất cả các phương thức gọi lại ActiveRecord của tôi có phải là riêng tư không?
- 15. Ruby on Rails: cung cấp vs content_for
- 16. Ruby on Rails/ActiveRecord và Bảng phân vùng
- 17. Ruby on Rails ActiveRecord nơi thuộc tính không trống
- 18. Ruby on Rails before_filter vs ruby khởi tạo
- 19. Gem Vs Plugin Vs Engine trong Ruby on Rails
- 20. Ruby - phạm vi từ vựng vs Inheritance
- 21. Ruby on Rails phương pháp xác định cho mảng
- 22. Rails 3 ActiveRecord mong muốn tải phạm vi
- 23. Ruby on Rails: cách sử dụng OAuth2 :: AccessToken.post? phương pháp
- 24. Lỗi Rake Ruby on Rails
- 25. Không thể chuyển đổi Phạm vi thành Số nguyên (Ruby on Rails)
- 26. Node.js và Ruby on Rails
- 27. Ruby on Rails: Đơn vị kiểm tra mô hình phi activerecord và vẫn tải đồ đạc
- 28. Ruby/Rails - Tôi có thể sử dụng phạm vi (hoặc phương thức lớp) của bảng đã tham gia như một phần của mệnh đề WHERE của tôi không?
- 29. Relation trên phạm vi trên ActiveRecord
- 30. Phản ứng, Ruby on Rails: jsx vs html.erb
Bài viết thú vị và thảo luận về chủ đề trong [bài đăng trên blog này] (http://www.justinweiss.com/articles/should-you-use-scopes-or-class-methods/) –