不一致的结果通过has_many加载关联

时间:2014-07-03 09:26:07

标签: ruby-on-rails

使用has_many :through加载关联时,如下面的代码示例所示(自包含/正在执行),导致意外记录加载,如断言失败所示。我不确定是否遗漏了测试通过。

unless File.exist?('Gemfile')
  File.write('Gemfile', <<-GEMFILE)
    source 'https://rubygems.org'
    gem 'rails', '4.1.4'
    gem 'sqlite3'
  GEMFILE

  system 'bundle'
end

require 'bundler'
Bundler.setup(:default)

require 'active_record'
require 'minitest/autorun'
require 'logger'

ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do
  create_table "blogs" do |t|
    t.integer :subject_id
    t.integer :author_id
  end

  create_table "subjects"
  create_table "authors"
end

class Subject < ActiveRecord::Base
  has_many :blogs, dependent: :destroy
end

class Blog < ActiveRecord::Base
  belongs_to :subject
  belongs_to :author
end

class Author < ActiveRecord::Base
  has_many :all_blogs_with_subject, through: :subjects, source: :blogs
  has_many :blogs
  has_many :subjects, through: :blogs
end

class HasManyThroughLoadTest < Minitest::Test
  def test_loading_associations_via_has_many_through
    author_one = Author.create!
    author_two = Author.create!
    Subject.create!(blogs: [Blog.new(author: author_one), Blog.new(author: author_one)])
    Subject.create!(blogs: [Blog.new(author: author_one), Blog.new(author: author_two)])

    # Expected 1, Actual 2 (also includes author_one's blog)
    assert_equal 1, author_two.reload.all_blogs_with_subject.size

    # Expected 3, Actual 4 (also includes author_two's blog)
    assert_equal 3, author_one.reload.all_blogs_with_subject.uniq.size
  end
end

1 个答案:

答案 0 :(得分:1)

我认为rails很难将所有这些表连接在一起。这就是你得到错误结果的原因。

基本上您正在执行以下操作:作者 - &gt;博客 - &gt;主题 - &gt;博客

如果您只是通过博客加入主题,则无需返回博客:

class Blog < ActiveRecord::Base
  belongs_to :subject
  belongs_to :author

  scope :with_subject, -> { joins(:subject) }
end

class HasManyThroughLoadTest < Minitest::Test
  def test_loading_associations_via_has_many_through
    author_one = Author.create!
    author_two = Author.create!
    Subject.create!(blogs: [Blog.new(author: author_one), Blog.new(author: author_one)])
    Subject.create!(blogs: [Blog.new(author: author_one), Blog.new(author: author_two)])

    # Expected 1, Actual 2 (also includes author_one's blog) 
    assert_equal 1, author_two.reload.blogs.with_subject.size

    # Expected 3, Actual 4 (also includes author_two's blog)
    assert_equal 3, author_one.reload.blogs.with_subject.uniq.size
  end
end