У 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.