作为从 Rails 3.2 迁移到 Rails 4 的一部分,所有命名范围都需要一个 proc 块。在这里阅读更多:http: //edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#active-record
我错过了更新我的一个模型中的范围,最终在我迁移后在生产中咬了我。所以我想弄清楚如何测试这个问题,我发现了一些奇怪的行为。
在某些情况下,如果没有 proc,范围似乎可以正常工作,但在其他情况下则不行。
# 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
现在,如果我编辑我的模型以将 proc 添加到第二个命名范围,如下所示:
class Offer < ActiveRecord::Base
scope :roster, where(:on_roster => true)
scope :commit, -> { where("status_id > 5") }
end
如果定义了 proc 的命名范围位于链的末尾,它将使用两组约束构建查询。但是,如果未定义 proc 的命名范围位于链的末尾,则生成的查询将在没有定义 proc 的范围约束的情况下构建。
$ 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
所以第一个结果是正确的,并且加载了两个范围,但第二个结果不正确,只加载了最后一个范围。然后,如果您将两个范围都更改为使用 procs,如下所示:
# 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
关于这一点,在您更新并保存模型后,在 rails 控制台中调用reload!
不会更新范围的行为。您必须结束您的 rails 控制台会话并开始一个新的会话,以使 proc 与非 proc 正确拾取。
我的问题是如何测试以确保我的所有范围都按预期运行?每次我想测试它们是否有 proc 或 lambda 块时,将作用域链接在一起似乎非常混乱。然而,我在示波器上设置的简单测试告诉我,我所有的示波器都通过了,并给出了假阳性结果。
有没有一种简单的方法可以通过 Rspec 和 Rails4 测试命名范围是否位于 proc 或 lambda 块中?