В рамках миграции с Rails 3.2 на Rails 4 все именованные области видимости нуждаются в блоке proc. Подробнее читайте здесь: http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#active-record
Я пропустил обновление прицела в одной из моих моделей, что привело к укусам меня в продакшене после миграции. Итак, я хотел выяснить, как проверить эту проблему, и обнаружил странное поведение.
В некоторых случаях осциллографы работают нормально без процедуры, но не в других случаях.
# models/offer.rb
class Offer < ActiveRecord::Base
scope :roster, where(:on_roster => true)
scope :commit, where("status_id > 5")
end
Если я использую каждую опцию области видимости для независимых вызовов в консоли rails, запросы строятся правильно, и результаты возвращаются, как и следовало ожидать в Rails 3.2:
$ rails c
2.0.0-p247 :001 > Offer.roster.all.size
Offer Load (1.6ms) SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't'
=> 1
2.0.0-p247 :002 > Offer.commit.all.size
Offer Load (1.6ms) SELECT "offers".* FROM "offers" WHERE (status_id > 5)
=> 3
Однако, если я объединю два вызова области видимости вместе в консоли rails, в каждый запрос будут включены только ограничения из последней области в цепочке:
2.0.0-p247 :003 > Offer.roster.commit.all.size
Offer Load (1.4ms) SELECT "offers".* FROM "offers" WHERE (status_id > 5)
=> 3
2.0.0-p247 :004 > Offer.commit.roster.all.size
Offer Load (0.7ms) SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't'
=> 1
Теперь, если я отредактирую свою модель, чтобы добавить процесс во вторую названную область, например:
class Offer < ActiveRecord::Base
scope :roster, where(:on_roster => true)
scope :commit, -> { where("status_id > 5") }
end
Если именованная область с определенной процедурой находится в конце цепочки, она построит запрос с обоими наборами ограничений. Однако, если именованная область без определенной процедуры находится в конце цепочки, результирующий запрос строится без ограничений области с определенной процедурой.
$ rails c
2.0.0-p247 :003 > Offer.roster.commit.all.size
Offer Load (1.4ms) SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't' AND (status_id > 5)
=> 0
2.0.0-p247 :004 > Offer.commit.roster.all.size
Offer Load (0.7ms) SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't'
=> 1
Итак, первый результат правильный и загружает обе области, а второй неверен и загружает только последнюю область. Затем, если вы измените обе области для использования процедур, например:
# models/offer.rb
class Offer < ActiveRecord::Base
scope :roster, -> { where(:on_roster => true) }
scope :commit, -> { where("status_id > 5") }
end
Наконец-то вы получите ожидаемое поведение:
$ rails c
2.0.0-p247 :002 > Offer.roster.commit.all.size
Offer Load (1.3ms) SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't' AND (status_id > 5)
=> 0
2.0.0-p247 :001 > Offer.commit.roster.all.size
Offer Load (1.7ms) SELECT "offers".* FROM "offers" WHERE "offers"."on_roster" = 't' AND (status_id > 5)
=> 0
Одно замечание по этому поводу: вызов reload!
в консоли rails не приведет к обновлению поведения осциллографов после того, как вы обновили и сохранили свою модель. Вы должны завершить сеанс консоли rails и начать новый, чтобы правильно выбрать proc и non-proc.
У меня возникает вопрос, как протестировать, чтобы убедиться, что все мои осциллографы будут вести себя так, как ожидалось? Объединение областей видимости в цепочку каждый раз, когда я хочу проверить, есть ли у них блок процедур или лямбда, кажется очень беспорядочным. Однако простые тесты, которые я проводил на прицелах, показали, что все мои прицелы проходят успешно и дают ложноположительные результаты.
Есть ли простой способ проверить с помощью Rspec с Rails4, находится ли указанная область в блоке процедуры или лямбда?