构建ActiveRecord关系而不执行查询

rai*_*inz 13 activerecord ruby-on-rails

我正在尝试构建一个查询,如下所示:

rel = article.where(version: 'some_version')
             .joins(:categories)
             .merge(Category.where(:uuid => 'some_cat_uuid'))

articles = rel.where(published: true).limit(10)
# etc.
Run Code Online (Sandbox Code Playgroud)

问题是无论我做什么,第一个查询似乎都会执行.难道我做错了什么?

nzi*_*nab 24

在控制台中运行命令时,它会自动添加类似于.inspect末尾的命令以显示命令的结果.例如(这是我现在正在处理的应用程序):

irb(main):061:0> Job.where(id: 251000)
  Job Load (3.8ms)  SELECT "jobs".* FROM "jobs" WHERE "jobs"."deleted_at" IS NULL AND "jobs"."id" = 251000
=> [#<Job id: 251000, {...}>]
Run Code Online (Sandbox Code Playgroud)

因此,您的第一行代码很好,通常不会执行查询,但由于您在控制台中运行它,它会立即执行,以便它可以显示结果.

解决这个问题的一种方法是添加; nil到命令的末尾,这样控制台就不会尝试显示结果(它只会显示nil作为该行的结果.IE:

irb(main):062:0> Job.where(id: 251000); nil
=> nil
Run Code Online (Sandbox Code Playgroud)

这样做你应该能够做你期望的事情(延迟执行查询,直到你真正需要结果):

rel = article.where(version: 'some_version')
             .joins(:categories)
             .merge(Category.where(:uuid => 'some_cat_uuid')); nil

articles = rel.where(published: true).limit(10); nil
Run Code Online (Sandbox Code Playgroud)

然后你可以使用articles.all(在Rails 3中)或articles.to_a(在Rails 4中)执行查询

当然,如果你随后将这些代码移动到rake任务或模型或其他东西,你可以放弃那些; nil位,因为它们看起来有点混乱,在那一点上没用.

控制台的另一个争论点可能是它会看到.where() {NEWLINE}并在那时执行查询,我倾向于将点放在上一行以消除我的命令结束位置的任何歧义:

rel = article.where(version: 'some_version').
             joins(:categories).
             merge(Category.where(:uuid => 'some_cat_uuid')); nil
Run Code Online (Sandbox Code Playgroud)

  • @Crazydog 是的,但那是因为那些不是延迟加载的方法。无论它们从何处运行,这些方法都会立即加载。 (5认同)
  • 看起来这只适用于[ActiveRecord :: QueryMethods](http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html)(`where`,`join`,`group`等).它不适用于[ActiveRecord :: FinderMethods](http://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html)(`first`,`find`,`find_by`等).`FinderMethods`将立即执行查询而不管`; nil`语法. (4认同)