Rails 5.2中的合并范围与Rails 5.1有何不同? [英] How are joins in scopes in Rails 5.2 different from rails 5.1?

查看:58
本文介绍了Rails 5.2中的合并范围与Rails 5.1有何不同?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将Rails从5.1升级到5.2后,我开始出现以下错误:

After I upgraded rails from 5.1 to 5.2 I started getting the following error:

NoMethodError: undefined method `expr' for nil:NilClass
  from /gems_path/activerecord-5.2.0/lib/active_record/associations/join_dependency/join_association.rb:47:in `block in join_constraints'
  from /gems_path/activerecord-5.2.0/lib/active_record/associations/join_dependency/join_association.rb:33:in `reverse_each'
  from /gems_path/activerecord-5.2.0/lib/active_record/associations/join_dependency/join_association.rb:33:in `join_constraints'
  from /gems_path/activerecord-5.2.0/lib/active_record/associations/join_dependency.rb:167:in `make_constraints'
  from /gems_path/activerecord-5.2.0/lib/active_record/associations/join_dependency.rb:177:in `make_join_constraints'
  from /gems_path/activerecord-5.2.0/lib/active_record/associations/join_dependency.rb:104:in `block in join_constraints'
  from /gems_path/activerecord-5.2.0/lib/active_record/associations/join_dependency.rb:103:in `each'
  from /gems_path/activerecord-5.2.0/lib/active_record/associations/join_dependency.rb:103:in `flat_map'
  from /gems_path/activerecord-5.2.0/lib/active_record/associations/join_dependency.rb:103:in `join_constraints'
  from /gems_path/activerecord-5.2.0/lib/active_record/relation/query_methods.rb:1026:in `build_join_query'
  from /gems_path/activerecord-5.2.0/lib/active_record/relation/query_methods.rb:1008:in `build_joins'
  from /gems_path/activerecord-5.2.0/lib/active_record/relation/query_methods.rb:928:in `build_arel'
  from /gems_path/activerecord-5.2.0/lib/active_record/relation/query_methods.rb:903:in `arel'
  from /gems_path/activerecord-5.2.0/lib/active_record/relation.rb:554:in `block in exec_queries'
  from /gems_path/activerecord-5.2.0/lib/active_record/relation.rb:578:in `skip_query_cache_if_necessary'
  from /gems_path/activerecord-5.2.0/lib/active_record/relation.rb:542:in `exec_queries'
  from /gems_path/activerecord-5.2.0/lib/active_record/relation.rb:414:in `load'
  from /gems_path/activerecord-5.2.0/lib/active_record/relation.rb:200:in `records'
  from /gems_path/activerecord-5.2.0/lib/active_record/relation/delegation.rb:41:in `[]'

导致错误的代码如下所示:

The code which causes the error looks the following way:

class Post
  has_many :comments

  has_one :last_comment, -> {
    joins("LEFT JOIN posts on posts.id = comments.post_id")
    .where("
      comments.id = (
        SELECT MAX(comments.id) FROM comments
        WHERE comments.post_id = posts.id
      )"
    )
  }, class_name: "Comment"

  scope :with_last_comment, -> { joins(:last_comment) }
end

我创建了此要点,其中包含有助于重现该错误的完整代码.将issue_with_joins_in_scopes_in_rails_5_3.rb下载到您的PC并使用

I created this gist which contains full code which helps to reproduce the bug. Download issue_with_joins_in_scopes_in_rails_5_3.rb to your PC and run it with

ruby issue_with_joins_in_scopes_in_rails_5_3.rb

您可以查看此Github问题以了解更多详情

You can look at this Github issue for more details

Rails 5.2和5.1中的联接之间有什么区别,导致代码Post.with_last_comment因Rails 5.2中的错误而失败?

What is the difference between joins in Rails 5.2 and 5.1 which causes the code Post.with_last_comment to fail with error in Rails 5.2?

如何在Post模型中更改last_comment关联和with_last_comment范围,使其在Rails 5.2中起作用?

How can I change last_comment association and with_last_comment scope in the Post model so it will work in Rails 5.2?

推荐答案

发布有关如何为帖子集合预加载最后评论的部分解决方案

Posting partial solution on how to preload last comment for a collection of posts

首先,您需要具有以下last_comment关联:

First you will need to have the following last_comment association:

class Post < ApplicationRecord
  has_many :comments, dependent: :destroy

  has_one :last_comment, -> { order(id: :desc) }, class_name: "Comment"
end

它与Rails 5.2中的preloadincludes一起使用,并生成以下SQL查询:

It works with preload and includes in Rails 5.2 and generates the following SQL queries:

Post.includes(:last_comment)

Post Load (0.2ms)  SELECT  "posts".* FROM "posts" LIMIT ?  [["LIMIT", 11]]
Comment Load (0.2ms)  SELECT "comments".* FROM "comments" WHERE "comments"."post_id" = ? ORDER BY "comments"."id" DESC  [["post_id", 1]]

此解决方案的问题在于,当我使用joins时,它将忽略关联范围并生成以下SQL查询:

The problem with this solution is that when I use joins it ignores association scope and generates the following SQL query:

Post.joins(:last_comment)

Post Load (0.2ms)  SELECT  "posts".* FROM "posts" INNER JOIN "comments" ON "comments"."post_id" = "posts"."id" LIMIT ?  [["LIMIT", 11]]

我能够通过以下方式更改原始的last_comment关联来解决该问题:

I was able to solve it changing the original last_comment association the following way:

class Post < ApplicationRecord
  has_many :comments, dependent: :destroy

  has_one :last_comment, -> {
    joins(:post)                               # <--- Note this change
    .where("
      comments.id = (
        SELECT MAX(comments.id) FROM comments
        WHERE comments.post_id = posts.id
      )"
    )
  }, class_name: "Comment"

  scope :with_last_comment, -> { joins(:last_comment) }
end

现在Post.with_last_comment生成以下SQL:

Post Load (0.3ms)  SELECT  "posts".* FROM "posts" INNER JOIN "comments" ON "comments"."post_id" = "posts"."id" INNER JOIN "posts" "posts_comments" ON "posts_comments"."id" = "comments"."post_id" AND (
      comments.id = (
        SELECT MAX(comments.id) FROM comments
        WHERE comments.post_id = posts.id
      )) LIMIT ?  [["LIMIT", 11]]

关于Rails 5.2中的联接与Rails 5.1有何不同的问题仍然悬而未决

The question on how joins in Rails 5.2 are different from Rails 5.1 is still open

这篇关于Rails 5.2中的合并范围与Rails 5.1有何不同?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆