Несогласованные результаты, загружающие ассоциацию через has_many через

#ruby-on-rails

#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:

Я думаю, rails с трудом объединяет все эти таблицы вместе. Вот почему вы получаете неправильные результаты.

В основном вы делаете следующее: Автор -> Блог -> Тема -> Блог

На самом деле вам не нужно возвращаться в блог, если вы просто присоединитесь к теме с помощью blog:

 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
  

Комментарии:

1. Да, последнее утверждение должно быть 3, а не 2. Обновлен вопрос.