Created
March 3, 2015 00:47
-
-
Save naw/fa55816dae7805355efd to your computer and use it in GitHub Desktop.
ThroughAssociation using same table twice (STI type and default_scope condition) problem
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
unless File.exist?('Gemfile') | |
File.write('Gemfile', <<-GEMFILE) | |
source 'https://rubygems.org' | |
gem 'rails', github: 'rails/rails' | |
gem 'arel', github: 'rails/arel' | |
gem 'sqlite3' | |
GEMFILE | |
system 'bundle' | |
end | |
require 'bundler' | |
Bundler.setup(:default) | |
require 'active_record' | |
require 'minitest/autorun' | |
require 'logger' | |
# Ensure backward compatibility with Minitest 4 | |
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test) | |
# This connection will do for database-independent bug reports. | |
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') | |
ActiveRecord::Base.logger = Logger.new(STDOUT) | |
ActiveRecord::Schema.define do | |
create_table :people, force: true do |t| | |
t.string :type | |
t.boolean :active, default: true | |
t.integer :parent_id | |
end | |
create_table :toys, force: true do |t| | |
t.integer :child_id | |
end | |
end | |
class Person < ActiveRecord::Base | |
end | |
class Parent < Person | |
end | |
class Child < Person | |
default_scope { where(active: true) } | |
belongs_to :parent | |
end | |
class Toy < ActiveRecord::Base | |
belongs_to :child | |
has_one :parent, through: :child | |
end | |
class BugTest < Minitest::Test | |
def test_has_one_through_sti_1 | |
# should get parent, but doesn't (in Rails 4.2) because STI type child is incorrectly | |
# applied to `people` table instead of `children_parent_join` table in query | |
# Fails in Rails 4.2 | |
# Passes in Rails master, but probably only due to a side effect of something else | |
parent = Parent.create! | |
child = Child.create!(parent: parent) | |
toy = Toy.create!(child: child) | |
assert_equal toy.parent, parent | |
end | |
def test_has_one_through_sti_2 | |
# should get parent, but doesn't because default_scope active | |
# is incorrectly applied to `people` table insetad of `children_parent_join` table in query | |
# Fails in Rails 4.2 and master | |
parent = Parent.create!(active: false) | |
child = Child.create!(parent: parent) | |
toy = Toy.create!(child: child) | |
assert_equal toy.parent, parent | |
end | |
def test_has_one_through_sti_3 | |
# should not get parent because child association is nil (due to default scope active) | |
# but the query puts the default scope on the wrong table, so child is found even though he is inactive | |
# and his parent is found too. | |
# | |
# Passes in Rails 4.2 (for the wrong reasons) | |
# Fails in master | |
parent = Parent.create! | |
child = Child.create!(parent: parent, active: false) | |
toy = Toy.create!(child: child) | |
toy.reload | |
assert_nil toy.child | |
assert_nil toy.parent | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
gem 'activerecord', '4.2.0' | |
require 'active_record' | |
require 'minitest/autorun' | |
require 'logger' | |
# Ensure backward compatibility with Minitest 4 | |
Minitest::Test = MiniTest::Unit::TestCase unless defined?(Minitest::Test) | |
# This connection will do for database-independent bug reports. | |
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:') | |
ActiveRecord::Base.logger = Logger.new(STDOUT) | |
ActiveRecord::Schema.define do | |
create_table :people, force: true do |t| | |
t.string :type | |
t.boolean :active, default: true | |
t.integer :parent_id | |
end | |
create_table :toys, force: true do |t| | |
t.integer :child_id | |
end | |
end | |
class Person < ActiveRecord::Base | |
end | |
class Parent < Person | |
end | |
class Child < Person | |
default_scope { where(active: true) } | |
belongs_to :parent | |
end | |
class Toy < ActiveRecord::Base | |
belongs_to :child | |
has_one :parent, through: :child | |
end | |
class BugTest < Minitest::Test | |
def test_has_one_through_sti_1 | |
# should get parent, but doesn't (in Rails 4.2) because STI type child is incorrectly | |
# applied to `people` table instead of `children_parent_join` table in query | |
# Fails in Rails 4.2 | |
# Passes in Rails master, but probably only due to a side effect of something else | |
parent = Parent.create! | |
child = Child.create!(parent: parent) | |
toy = Toy.create!(child: child) | |
assert_equal toy.parent, parent | |
end | |
def test_has_one_through_sti_2 | |
# should get parent, but doesn't because default_scope active | |
# is incorrectly applied to `people` table insetad of `children_parent_join` table in query | |
# Fails in Rails 4.2 and master | |
parent = Parent.create!(active: false) | |
child = Child.create!(parent: parent) | |
toy = Toy.create!(child: child) | |
assert_equal toy.parent, parent | |
end | |
def test_has_one_through_sti_3 | |
# should not get parent because child association is nil (due to default scope active) | |
# but the query puts the default scope on the wrong table, so child is found even though he is inactive | |
# and his parent is found too. | |
# | |
# Passes in Rails 4.2 (for the wrong reasons) | |
# Fails in master | |
parent = Parent.create! | |
child = Child.create!(parent: parent, active: false) | |
toy = Toy.create!(child: child) | |
toy.reload | |
assert_nil toy.child | |
assert_nil toy.parent | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment