diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG index 25addad806..ba7151ccbb 100644 --- a/activerecord/CHANGELOG +++ b/activerecord/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Fixed that has_and_belongs_to_many didn't respect single table inheritance types #1081 [Florian Weber] + * Speed up ActiveRecord#method_missing for the common case (read_attribute). * Only notify observers on after_find and after_initialize if these methods are defined on the model. [skaes@web.de] diff --git a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb index b34574161f..da43e32fb6 100644 --- a/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb +++ b/activerecord/lib/active_record/associations/has_and_belongs_to_many_association.rb @@ -158,6 +158,15 @@ module ActiveRecord "j.#{@association_class_primary_key_name} = #{@owner.quoted_id} " @finder_sql << " AND #{interpolate_sql(@options[:conditions])}" if @options[:conditions] + + unless @association_class.descends_from_active_record? + type_condition = @association_class.send(:subclasses).inject("t.#{@association_class.inheritance_column} = '#{@association_class.name.demodulize}' ") do |condition, subclass| + condition << "OR t.#{@association_class.inheritance_column} = '#{subclass.name.demodulize}' " + end + + @finder_sql << " AND (#{type_condition})" + end + @finder_sql << " ORDER BY #{@order}" if @order end end diff --git a/activerecord/test/associations_test.rb b/activerecord/test/associations_test.rb index e7160c9365..25b5457051 100755 --- a/activerecord/test/associations_test.rb +++ b/activerecord/test/associations_test.rb @@ -1105,4 +1105,18 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase new_developer.save assert_equal 2, new_developer.projects.length end + + def test_consider_type + developer = Developer.find(:first) + special_project = SpecialProject.create("name" => "Special Project") + + other_project = developer.projects.first + developer.special_projects << special_project + developer.reload + + assert developer.projects.include?(special_project) + assert developer.special_projects.include?(special_project) + assert !developer.special_projects.include?(other_project) + end + end diff --git a/activerecord/test/base_test.rb b/activerecord/test/base_test.rb index b6ae403ca0..74e03097aa 100755 --- a/activerecord/test/base_test.rb +++ b/activerecord/test/base_test.rb @@ -114,7 +114,7 @@ class BasicsTest < Test::Unit::TestCase end def test_attributes_hash - assert_equal @loaded_fixtures['projects']['active_record'].to_hash, Project.find(:first).attributes + assert_equal @loaded_fixtures['computers']['workstation'].to_hash, Computer.find(:first).attributes end def test_create diff --git a/activerecord/test/fixtures/db_definitions/db2.sql b/activerecord/test/fixtures/db_definitions/db2.sql index 40faf53269..90f57a0c08 100644 --- a/activerecord/test/fixtures/db_definitions/db2.sql +++ b/activerecord/test/fixtures/db_definitions/db2.sql @@ -44,6 +44,7 @@ CREATE TABLE developers ( CREATE TABLE projects ( id int generated by default as identity (start with +10000), name varchar(100) default NULL, + type varchar(255) default NULL, PRIMARY KEY (id) ); diff --git a/activerecord/test/fixtures/db_definitions/mysql.sql b/activerecord/test/fixtures/db_definitions/mysql.sql index cb589bec6f..d1d65194cb 100755 --- a/activerecord/test/fixtures/db_definitions/mysql.sql +++ b/activerecord/test/fixtures/db_definitions/mysql.sql @@ -45,6 +45,7 @@ CREATE TABLE `developers` ( CREATE TABLE `projects` ( `id` int(11) NOT NULL auto_increment, `name` varchar(100) default NULL, + `type` VARCHAR(255) NOT NULL, PRIMARY KEY (`id`) ) TYPE=InnoDB; diff --git a/activerecord/test/fixtures/db_definitions/oci.sql b/activerecord/test/fixtures/db_definitions/oci.sql index 0170215c41..43a54df604 100644 --- a/activerecord/test/fixtures/db_definitions/oci.sql +++ b/activerecord/test/fixtures/db_definitions/oci.sql @@ -63,6 +63,7 @@ create table developers ( create table projects ( id integer not null, name varchar(100) default null, + type varchar(255) default null, primary key (id) ); diff --git a/activerecord/test/fixtures/db_definitions/postgresql.sql b/activerecord/test/fixtures/db_definitions/postgresql.sql index aec5bd64c3..37f3ae5f29 100644 --- a/activerecord/test/fixtures/db_definitions/postgresql.sql +++ b/activerecord/test/fixtures/db_definitions/postgresql.sql @@ -37,6 +37,7 @@ SELECT setval('developers_id_seq', 100); CREATE TABLE projects ( id serial, name character varying(100), + type varchar(255), PRIMARY KEY (id) ); SELECT setval('projects_id_seq', 100); diff --git a/activerecord/test/fixtures/db_definitions/sqlite.sql b/activerecord/test/fixtures/db_definitions/sqlite.sql index 1e3b4769f2..ab06d4a4d7 100644 --- a/activerecord/test/fixtures/db_definitions/sqlite.sql +++ b/activerecord/test/fixtures/db_definitions/sqlite.sql @@ -40,7 +40,8 @@ CREATE TABLE 'developers' ( CREATE TABLE 'projects' ( 'id' INTEGER PRIMARY KEY NOT NULL, - 'name' TEXT DEFAULT NULL + 'name' TEXT DEFAULT NULL, + 'type' VARCHAR(255) DEFAULT NULL ); CREATE TABLE 'developers_projects' ( diff --git a/activerecord/test/fixtures/db_definitions/sqlserver.sql b/activerecord/test/fixtures/db_definitions/sqlserver.sql index 2280bc80ea..6a15c0cbfd 100644 --- a/activerecord/test/fixtures/db_definitions/sqlserver.sql +++ b/activerecord/test/fixtures/db_definitions/sqlserver.sql @@ -39,7 +39,8 @@ CREATE TABLE developers ( CREATE TABLE projects ( id int NOT NULL IDENTITY(1, 1) PRIMARY KEY, - name varchar(100) default NULL + name varchar(100) default NULL, + type varchar(255) default NULL ); CREATE TABLE developers_projects ( diff --git a/activerecord/test/fixtures/developer.rb b/activerecord/test/fixtures/developer.rb index 6d01490844..17d0746cfa 100644 --- a/activerecord/test/fixtures/developer.rb +++ b/activerecord/test/fixtures/developer.rb @@ -1,6 +1,7 @@ class Developer < ActiveRecord::Base has_and_belongs_to_many :projects - + has_and_belongs_to_many :special_projects, :join_table => 'developers_projects', :association_foreign_key => 'project_id' + validates_inclusion_of :salary, :in => 50000..200000 validates_length_of :name, :within => 3..20 end diff --git a/activerecord/test/fixtures/subscriber.rb b/activerecord/test/fixtures/subscriber.rb index 3f1ade0d83..e5e11724fd 100644 --- a/activerecord/test/fixtures/subscriber.rb +++ b/activerecord/test/fixtures/subscriber.rb @@ -3,3 +3,6 @@ class Subscriber < ActiveRecord::Base "nick" end end + +class SpecialSubscriber < Subscriber +end \ No newline at end of file diff --git a/activerecord/test/inheritance_test.rb b/activerecord/test/inheritance_test.rb index dbbbb6eee7..7c309a7ba3 100755 --- a/activerecord/test/inheritance_test.rb +++ b/activerecord/test/inheritance_test.rb @@ -1,9 +1,10 @@ require 'abstract_unit' require 'fixtures/company' require 'fixtures/project' +require 'fixtures/subscriber' class InheritanceTest < Test::Unit::TestCase - fixtures :companies, :projects + fixtures :companies, :projects, :subscribers def test_a_bad_type_column #SQLServer need to turn Identity Insert On before manually inserting into the Identity column @@ -125,9 +126,8 @@ class InheritanceTest < Test::Unit::TestCase end def test_inheritance_without_mapping - assert_kind_of SpecialProject, SpecialProject.find(1) - assert_nothing_raised { SpecialProject.create("name" => "And breaaaaathe!") } - + assert_kind_of SpecialSubscriber, SpecialSubscriber.find("webster132") + assert_nothing_raised { SpecialSubscriber.create("name" => "And breaaaaathe!", "id" => "smartass") } end private