Với Rails 4, Model.scoped không được dùng nữa nhưng Model.all không thể thay thế nó


76

Khởi động Rails 4, Model.scopedhiện không được dùng nữa.

DEPRECATION WARNING: Model.scoped is deprecated. Please use Model.all instead.

Nhưng, có một sự khác biệt trong Model.scopedModel.all, đó là scoped.scopedtrả về một phạm vi, trong khi all.allchạy truy vấn.

Trên đường ray 3:

> Model.scoped.scoped.is_a?(ActiveRecord::Relation)
=> true

Trên đường ray 4:

> Model.all.all.is_a?(ActiveRecord::Relation)
DEPRECATION WARNING: Relation#all is deprecated. If you want to eager-load a relation, you can call #load (e.g. `Post.where(published: true).load`). If you want to get an array of records from a relation, you can call #to_a (e.g. `Post.where(published: true).to_a`).
=> false

Có những trường hợp sử dụng trong thư viện / mối quan tâm trả về scopedkhi có điều kiện để làm điều gì đó hoặc không làm gì, như vậy:

module AmongConcern
  extend ActiveSupport::Concern

  module ClassMethods
    def among(ids)
      return scoped if ids.blank?

      where(id: ids)
    end
  end
end

Nếu bạn thay đổi điều này scopedthành all, bạn sẽ gặp phải các vấn đề ngẫu nhiên tùy thuộc vào vị trí amongđược sử dụng trong chuỗi phạm vi. Ví dụ: Model.where(some: value).among(ids)sẽ chạy truy vấn thay vì trả về một phạm vi.

Những gì tôi muốn là một phương thức idmpotent ActiveRecord::Relationchỉ đơn giản là trả về một phạm vi.

Tôi nên làm gì ở đây?


Bạn có chắc rằng nội dung " allchạy truy vấn" không chỉ là tạo tác của bảng điều khiển? Nguồn tin gợi ý rằng nó sẽ hoạt động tốt.
mu quá ngắn


Nhưng bạn không nhận được cảnh báo đó vì vậy bạn đang nhận được alltừ scoping/named.rb, phải không? Và alltừ scoping/named.rblà, AFAIK, những gì Model.allsử dụng.
mu quá ngắn


Câu trả lời:


64

Có vẻ như đó where(nil)là một sự thay thế thực sự của scoped, hoạt động trên cả Rails 3 và 4. :(


1
Cảnh báo không dùng nữa cho biết sử dụng load.
shanemcd

nó nói để sử dụng loadnếu bạn muốn nạp háo hức, và trong mọi trường hợp phải mất một tham số (điều kiện), vì vậy bây giờ where(nil)(hoặc truehoặc {}hoặc 1) dường như là sự thay thế tốt nhất củascoped
ecoologic

Không hoạt động đối với trường hợp của tôi: user.active_section.scoped.uniq(false)hoạt động, user.active_section.all.uniq(false)hoặc user.active_section.where(nil).uniq(false)không.
Skully

Làm thế nào về đường ray 5?
Chamnap

25

Trên Rails 4.1 (beta 1), các hoạt động sau:

Model.all.all.is_a?(ActiveRecord::Relation)
=> true

Vì vậy, có vẻ như vấn đề này đã được khắc phục và trong 4.1.0 Model.scopedđã được loại bỏ hoàn toàn.


2
Tuyệt vời, cảm ơn vì đã cập nhật! Tuy nhiên nếu bạn là một nhà duy trì đá quý, bạn phải tiếp tục sử dụng where(nil)cho đến khi 4.0.x trở nên không được hỗ trợ ...
Kenn

Đây là một chủ đề rất cũ nhưng chúng tôi chỉ đang nâng cấp bây giờ và phải duy trì hỗ trợ cho Rails 3 và 4. Có hợp lý để làm một cái gì đó dọc theo dòng của if ActiveRecord::VERSION::MAJOR == 3 then Model.scoped else Model.all end?
astorije

9

Như đã đề cập trong một trong các nhận xét, allđược cho là trả về một phạm vi theo tài liệu .

Tài liệu đúng - nó trả về ActiveRecord :: Relation, nhưng bạn phải sử dụng dấu chấm phẩy nếu muốn xem nó trong bảng điều khiển:

pry(main)> u = User.all;

pry(main)> u.class

=> ActiveRecord::Relation::ActiveRecord_Relation_User

Nó không liên quan - hãy thử User.all.all;và bạn nhận được cảnh báo tương tự. Thật không may, nó sẽ không được sửa cho đến khi Rails 4.x hoặc thậm chí là Rails 5. github.com/rails/rails/issues/12756
kenn

4

Ngoài việc sử dụng, where(nil)bạn cũng có thể gọi clonenếu bạn biết đó selflà Relation và nhận được hành vi giống hệt như gọi scopedmà không có args, không có cảnh báo phản đối.

BIÊN TẬP

Tôi hiện đang sử dụng mã này để thay thế scopedvì tôi không thích sử dụng where(nil)ở mọi nơi mà tôi cần nắm giữ phạm vi hiện tại:

     # config/initializers/scoped.rb
     class ActiveRecord::Base
       # do things the modern way and silence Rails 4 deprecation warnings
       def self.scoped(options=nil)
         options ? where(nil).apply_finder_options(options, true) : where(nil)
       end
     end

Tôi không thấy lý do tại sao các tác giả AR không thể làm một cái gì đó tương tự kể từ khi các điểm OP ra allscopedlàm không cư xử như vậy.


Bạn không thể gọi clonetrên một lớp người mẫu. (ví dụ Model.clone) scopedđã làm việc trên cả các lớp mô hình và các quan hệ.
kenn

@kenn Yep, do đó tại sao tôi nói 'nếu bạn biết rằng bản thân là một Mối quan hệ' ở trên.
Andrew Hacking,
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.