У Rails 4 модель Model.scoped застаріла, але Model.all не може її замінити


76

Запуск Rails 4 Model.scopedтепер застарілий.

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

Але є різниця в Model.scopedі Model.all, тобто, scoped.scopedповертає область, під час all.allзапуску запиту.

На рейках 3:

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

На рейках 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

Є випадки використання в бібліотеках / проблеми, які повертаються, scopedколи є умова зробити щось або нічого, наприклад:

module AmongConcern
  extend ActiveSupport::Concern

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

      where(id: ids)
    end
  end
end

Якщо ви зміните це scopedна all, ви зіткнетеся з випадковими проблемами, залежно від того, де amongбуло використано в ланцюжку області. Наприклад, Model.where(some: value).among(ids)виконував би запит, а не повертав область.

Що я хочу, це ідемпотентний метод, ActiveRecord::Relationякий просто повертає область.

Що мені тут робити?


Ви впевнені, що " allзапуск запиту" - це не просто артефакт консолі? Джерело припускає, що це повинно працювати дуже добре.
— mu занадто короткий


Але ви не отримуєте цього попередження, тому отримуєте allз scoping/named.rb, так? І allвід того scoping/named.rb, що AFAIK Model.allвикористовує.
— mu занадто короткий


Відповіді:


64

Здається, where(nil)це справжня заміна scoped, яка працює як на Rails 3, так і на 4. :(


1
У попередженні про припинення використання сказано використовувати load.
— shanemcd

там сказано використовувати loadЯКЩО ви хочете охоче завантажувати, і в будь-якому випадку він бере параметр (умова), тому на даний момент where(nil)(або trueабо {}або 1) здається найкращою заміноюscoped
— ecoologic

Не працює в моєму випадку: user.active_section.scoped.uniq(false)працює user.active_section.all.uniq(false)чи user.active_section.where(nil).uniq(false)ні.
— Skully

Як щодо рейок 5?
— Chamnap

25

На Rails 4.1 (бета-версія 1) працює наступне:

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

Отже, ця проблема була виправлена ​​і в 4.1.0 Model.scopedвзагалі видалена.


2
Чудово, дякую за оновлення! Однак якщо ви підтримуєте дорогоцінний камінь, ви повинні продовжувати використовувати його where(nil)до тих пір, поки 4.0.x не стане підтримуваним ...
— kenn

Це дуже стара нитка, але ми модернізуємо її лише зараз і також повинні підтримувати підтримку Rails 3 і 4. Чи розумно робити щось подібне if ActiveRecord::VERSION::MAJOR == 3 then Model.scoped else Model.all end?
— astorije

9

Як зазначалося в одному з коментарів, allпередбачається повернути область застосування згідно з документами .

Документи правильні - він повертає ActiveRecord :: Relation, але вам потрібно використовувати крапку з комою, якщо ви хочете побачити це в консолі:

pry(main)> u = User.all;

pry(main)> u.class

=> ActiveRecord::Relation::ActiveRecord_Relation_User

Це неактуально - спробуйте, User.all.all;і ви отримаєте те саме попередження. На жаль, це не буде виправлено до Rails 4.x або навіть Rails 5. github.com/rails/rails/issues/12756
— kenn

4

На додаток до використання, where(nil)ви також можете зателефонувати, cloneякщо знаєте, що selfце "Відношення", і отримати однакову поведінку виклику scopedбез аргументів, без попередження про припинення використання.

РЕДАГУВАТИ

Зараз я використовую цей код як падіння заміни, scopedоскільки мені не подобається використовувати where(nil)всюди, де мені потрібно дістати поточну область:

     # 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

Я не розумію , чому автори AR не могли б зробити що - щось подібне , так як точки OP , виконаними allі scopedнічого НЕ поводяться так само.


Ви не можете зателефонувати cloneдо класу моделі. (наприклад Model.clone) scopedпрацював як на модельних класах, так і на відносинах.
— kenn

@kenn Так, отже, чому я сказав вище, "якщо ти знаєш, що Я є Співвідношенням".
— Ендрю Хакінг,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.