Rails has_many与`through`选项“失去”连接?

时间:2014-12-03 15:41:43

标签: ruby-on-rails rails-activerecord has-many-through

我有以下示例模型结构:

class Category < ActiveRecord::Base
  has_many :posts

  scope :active, -> { where(active: true) }
end

class User < ActiveRecord::Base
  has_many :posts
  has_many :visible_posts, -> { joins(:category).merge(Category.active) }, class: Post
  has_many :visible_posts_comments, through: :visible_posts, source: :comments

  has_many :comments
end

class Post < ActiveRecord::Base
  belongs_to :category
  belongs_to :user
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :post
  belongs_to :user
end

现在User.first.visible_posts_comments引发了以下错误:

ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR:  missing FROM-clause entry for table "categories"
LINE 1: ..." = "posts"."id" WHERE "posts"."user_id" = $1 AND "categorie...

这是因为此关联执行的SQL如下:

2.1.2 :009 > u.visible_posts_comments.to_sql
 => "SELECT \"comments\".* FROM \"comments\" INNER JOIN \"posts\" ON \"comments\".\"post_id\" = \"posts\".\"id\" WHERE \"posts\".\"user_id\" = $1 AND \"categories\".\"active\" = 't'"

visible_postsINNER JOIN上添加categories后,2.1.2 :010 > u.visible_posts.to_sql => "SELECT \"posts\".* FROM \"posts\" INNER JOIN \"categories\" ON \"categories\".\"id\" = \"posts\".\"category_id\" WHERE \"posts\".\"user_id\" = $1 AND \"categories\".\"active\" = 't'" 正常工作,

visible_posts_comments

为什么joins(:category)似乎“丢失”merge(Category.active)语句但保留through?我认为没有理由故意放弃{{1}} - 联盟的联接。这是一个错误还是一个功能?

我使用的是activerecord-4.1.8。

可与此相关:https://github.com/rails/rails/issues/17904

1 个答案:

答案 0 :(得分:3)

我创建了与您相同的rails项目,发现了同样的问题。 关于这个问题有两点:

1。 has_many:通过将删除&#34;加入&#34;从通过关系,源代码:

#lib/active_record/associations/through_association.rb  line 14
    def target_scope
      scope = super
      chain.drop(1).each do |reflection|
        relation = reflection.klass.all
        relation.merge!(reflection.scope) if reflection.scope

        scope.merge!(
          relation.except(:select, :create_with, :includes, :preload, :joins, :eager_load)
        )

      end
      scope
    end

我认为他们这样做的原因是记录创建操作的考虑因素。恩。也许u.visible_posts_comments.create(...)会使ActiveRecord感到困惑

2。一种适合您的方式:

class Category < ActiveRecord::Base
  has_many :posts
end

class User < ActiveRecord::Base
  has_many :posts
  has_many :visible_posts, -> { merge(Post.active) }, class: Post
  has_many :visible_posts_comments, -> { joins(:post).merge(Post.active) }, class: Comment

  has_many :comments
end

class Post < ActiveRecord::Base
  belongs_to :category
  belongs_to :user
  has_many :comments

  scope :active, -> { joins(:category).merge(Category.active) }
end

class Comment < ActiveRecord::Base
  belongs_to :post
  belongs_to :user
end