db2 2.6.2 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. data/CHANGES +17 -0
  2. data/README +79 -141
  3. data/ext/Makefile.nt32 +3 -3
  4. data/ext/Makefile.nt32.191 +212 -0
  5. data/ext/extconf.rb +75 -14
  6. data/ext/ibm_db.c +504 -47
  7. data/ext/ruby_ibm_db.h +4 -1
  8. data/ext/ruby_ibm_db_cli.c +108 -1
  9. data/ext/ruby_ibm_db_cli.h +54 -1
  10. data/lib/active_record/connection_adapters/ibm_db_adapter.rb +423 -124
  11. data/lib/active_record/connection_adapters/ibm_db_pstmt.rb +1 -1
  12. data/test/cases/adapter_test.rb +169 -164
  13. data/test/cases/associations/belongs_to_associations_test.rb +268 -43
  14. data/test/cases/associations/cascaded_eager_loading_test.rb +31 -33
  15. data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +90 -156
  16. data/test/cases/associations/join_model_test.rb +100 -150
  17. data/test/cases/attribute_methods_test.rb +259 -58
  18. data/test/cases/base_test.rb +785 -138
  19. data/test/cases/calculations_test.rb +128 -8
  20. data/test/cases/migration_test.rb +680 -286
  21. data/test/cases/persistence_test.rb +642 -0
  22. data/test/cases/query_cache_test.rb +257 -0
  23. data/test/cases/relations_test.rb +1182 -0
  24. data/test/cases/schema_dumper_test.rb +41 -17
  25. data/test/cases/transaction_callbacks_test.rb +300 -0
  26. data/test/cases/validations/uniqueness_validation_test.rb +38 -22
  27. data/test/cases/xml_serialization_test.rb +408 -0
  28. data/test/config.yml +154 -0
  29. data/test/connections/native_ibm_db/connection.rb +2 -0
  30. data/test/models/warehouse_thing.rb +4 -4
  31. data/test/schema/i5/ibm_db_specific_schema.rb +3 -1
  32. data/test/schema/ids/ibm_db_specific_schema.rb +3 -1
  33. data/test/schema/luw/ibm_db_specific_schema.rb +2 -0
  34. data/test/schema/schema.rb +196 -92
  35. data/test/schema/zOS/ibm_db_specific_schema.rb +3 -1
  36. metadata +73 -68
  37. data/.gitignore +0 -1
  38. data/test/cases/associations/eager_test.rb +0 -862
  39. data/test/cases/associations/has_many_through_associations_test.rb +0 -461
  40. data/test/cases/finder_test.rb +0 -1088
  41. data/test/cases/fixtures_test.rb +0 -684
@@ -177,7 +177,7 @@ module ActiveRecord
177
177
  end
178
178
 
179
179
  pstmt = connection.prepare(statement, "#{self.class.name} Create")
180
- self.id = connection.prepared_insert(pstmt, quoted_attributes.values)
180
+ self.id = connection.prepared_insert(pstmt, quoted_attributes.values, self.id)
181
181
 
182
182
  @new_record = false
183
183
  id
@@ -1,202 +1,207 @@
1
1
  require "cases/helper"
2
2
 
3
- class AdapterTest < ActiveRecord::TestCase
4
- def setup
5
- @connection = ActiveRecord::Base.connection
6
- end
3
+ module ActiveRecord
4
+ class AdapterTest < ActiveRecord::TestCase
5
+ def setup
6
+ @connection = ActiveRecord::Base.connection
7
+ end
7
8
 
8
- if current_adapter?(:IBM_DBAdapter)
9
- def test_a_connection_attributes
10
- if @connection.servertype.class.name.include?('::IBM_IDS')
11
- return
12
- end
13
- if @connection.respond_to?(:schema)
14
- previous_schema = ActiveRecord::Base.connection.schema
15
- ActiveRecord::Base.connection.schema = 'SYSCAT'
16
- assert_equal 'SYSCAT', ActiveRecord::Base.connection.schema
17
- ActiveRecord::Base.connection.schema = previous_schema
18
- else
19
- warn "#{@connection.class} does not support client connection attribute schema_name"
20
- end
21
-
22
- if @connection.respond_to?(:app_user)
23
- ActiveRecord::Base.connection.app_user = 'new_user'
24
- assert_equal 'new_user', ActiveRecord::Base.connection.app_user
25
- else
26
- warn "#{@connection.class} does not support client connection attribute SQL_ATTR_INFO_USER"
27
- end
28
-
29
- if @connection.respond_to?(:account)
30
- ActiveRecord::Base.connection.account = 'new_acct'
31
- assert_equal 'new_acct', ActiveRecord::Base.connection.account
32
- else
33
- warn "#{@connection.class} does not support client connection attribute SQL_ATTR_INFO_ACCTSTR"
34
- end
35
-
36
- if @connection.respond_to?(:application)
37
- ActiveRecord::Base.connection.application = 'new_app'
38
- assert_equal 'new_app', ActiveRecord::Base.connection.application
39
- else
40
- warn "#{@connection.class} does not support client connection attribute SQL_ATTR_INFO_APPLNAME"
9
+ if current_adapter?(:IBM_DBAdapter)
10
+ def test_a_connection_attributes
11
+ if @connection.servertype.class.name.include?('::IBM_IDS')
12
+ return
13
+ end
14
+ if @connection.respond_to?(:schema)
15
+ previous_schema = ActiveRecord::Base.connection.schema
16
+ ActiveRecord::Base.connection.schema = 'SYSCAT'
17
+ assert_equal 'SYSCAT', ActiveRecord::Base.connection.schema
18
+ ActiveRecord::Base.connection.schema = previous_schema
19
+ else
20
+ warn "#{@connection.class} does not support client connection attribute schema_name"
21
+ end
22
+
23
+ if @connection.respond_to?(:app_user)
24
+ ActiveRecord::Base.connection.app_user = 'new_user'
25
+ assert_equal 'new_user', ActiveRecord::Base.connection.app_user
26
+ else
27
+ warn "#{@connection.class} does not support client connection attribute SQL_ATTR_INFO_USER"
28
+ end
29
+
30
+ if @connection.respond_to?(:account)
31
+ ActiveRecord::Base.connection.account = 'new_acct'
32
+ assert_equal 'new_acct', ActiveRecord::Base.connection.account
33
+ else
34
+ warn "#{@connection.class} does not support client connection attribute SQL_ATTR_INFO_ACCTSTR"
35
+ end
36
+
37
+ if @connection.respond_to?(:application)
38
+ ActiveRecord::Base.connection.application = 'new_app'
39
+ assert_equal 'new_app', ActiveRecord::Base.connection.application
40
+ else
41
+ warn "#{@connection.class} does not support client connection attribute SQL_ATTR_INFO_APPLNAME"
42
+ end
43
+
44
+ if @connection.respond_to?(:workstation)
45
+ ActiveRecord::Base.connection.workstation = 'new_wrkst'
46
+ assert_equal 'new_wrkst', ActiveRecord::Base.connection.workstation
47
+ else
48
+ warn "#{@connection.class} does not support client connection attribute SQL_ATTR_INFO_WRKSTNNAME"
49
+ end
41
50
  end
51
+ end
42
52
 
43
- if @connection.respond_to?(:workstation)
44
- ActiveRecord::Base.connection.workstation = 'new_wrkst'
45
- assert_equal 'new_wrkst', ActiveRecord::Base.connection.workstation
53
+ def test_tables
54
+ tables = @connection.tables
55
+ assert tables.include?("accounts")
56
+ assert tables.include?("authors")
57
+ assert tables.include?("tasks")
58
+ assert tables.include?("topics")
59
+ end
60
+
61
+ def test_table_exists?
62
+ assert @connection.table_exists?("accounts")
63
+ assert !@connection.table_exists?("nonexistingtable")
64
+ assert !@connection.table_exists?(nil)
65
+ end
66
+
67
+ def test_indexes
68
+ idx_name = "accounts_idx"
69
+
70
+ if @connection.respond_to?(:indexes)
71
+ indexes = @connection.indexes("accounts")
72
+ assert indexes.empty?
73
+
74
+ @connection.add_index :accounts, :firm_id, :name => idx_name
75
+ indexes = @connection.indexes("accounts")
76
+ assert_equal "accounts", indexes.first.table
77
+ # OpenBase does not have the concept of a named index
78
+ # Indexes are merely properties of columns.
79
+ assert_equal idx_name, indexes.first.name unless current_adapter?(:OpenBaseAdapter)
80
+ assert !indexes.first.unique
81
+ assert_equal ["firm_id"], indexes.first.columns
46
82
  else
47
- warn "#{@connection.class} does not support client connection attribute SQL_ATTR_INFO_WRKSTNNAME"
83
+ warn "#{@connection.class} does not respond to #indexes"
48
84
  end
49
- end
50
- end
51
-
52
- def test_tables
53
- tables = @connection.tables
54
- assert tables.include?("accounts")
55
- assert tables.include?("authors")
56
- assert tables.include?("tasks")
57
- assert tables.include?("topics")
58
- end
59
85
 
60
- def test_table_exists?
61
- assert @connection.table_exists?("accounts")
62
- assert !@connection.table_exists?("nonexistingtable")
63
- end
64
-
65
- def test_indexes
66
- idx_name = "accounts_idx"
67
-
68
- if @connection.respond_to?(:indexes)
69
- indexes = @connection.indexes("accounts")
70
- assert indexes.empty?
71
-
72
- @connection.add_index :accounts, :firm_id, :name => idx_name
73
- indexes = @connection.indexes("accounts")
74
- assert_equal "accounts", indexes.first.table
75
- # OpenBase does not have the concept of a named index
76
- # Indexes are merely properties of columns.
77
- assert_equal idx_name, indexes.first.name unless current_adapter?(:OpenBaseAdapter)
78
- assert !indexes.first.unique
79
- assert_equal ["firm_id"], indexes.first.columns
80
- else
81
- warn "#{@connection.class} does not respond to #indexes"
86
+ ensure
87
+ @connection.remove_index(:accounts, :name => idx_name) rescue nil
82
88
  end
83
89
 
84
- ensure
85
- @connection.remove_index(:accounts, :name => idx_name) rescue nil
86
- end
87
-
88
- def test_current_database
89
- if @connection.respond_to?(:current_database)
90
- assert_equal ENV['ARUNIT_DB_NAME'] || "activerecord_unittest", @connection.current_database
90
+ def test_current_database
91
+ if @connection.respond_to?(:current_database)
92
+ assert_equal ARTest.connection_config['arunit']['database'], @connection.current_database
93
+ end
91
94
  end
92
- end
93
95
 
94
- if current_adapter?(:MysqlAdapter)
95
- def test_charset
96
- assert_not_nil @connection.charset
97
- assert_not_equal 'character_set_database', @connection.charset
98
- assert_equal @connection.show_variable('character_set_database'), @connection.charset
99
- end
96
+ if current_adapter?(:MysqlAdapter)
97
+ def test_charset
98
+ assert_not_nil @connection.charset
99
+ assert_not_equal 'character_set_database', @connection.charset
100
+ assert_equal @connection.show_variable('character_set_database'), @connection.charset
101
+ end
100
102
 
101
- def test_collation
102
- assert_not_nil @connection.collation
103
- assert_not_equal 'collation_database', @connection.collation
104
- assert_equal @connection.show_variable('collation_database'), @connection.collation
105
- end
103
+ def test_collation
104
+ assert_not_nil @connection.collation
105
+ assert_not_equal 'collation_database', @connection.collation
106
+ assert_equal @connection.show_variable('collation_database'), @connection.collation
107
+ end
106
108
 
107
- def test_show_nonexistent_variable_returns_nil
108
- assert_nil @connection.show_variable('foo_bar_baz')
109
- end
109
+ def test_show_nonexistent_variable_returns_nil
110
+ assert_nil @connection.show_variable('foo_bar_baz')
111
+ end
110
112
 
111
- def test_not_specifying_database_name_for_cross_database_selects
112
- begin
113
- assert_nothing_raised do
114
- ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['arunit'].except(:database))
115
- ActiveRecord::Base.connection.execute "SELECT activerecord_unittest.pirates.*, activerecord_unittest2.courses.* FROM activerecord_unittest.pirates, activerecord_unittest2.courses"
113
+ def test_not_specifying_database_name_for_cross_database_selects
114
+ begin
115
+ assert_nothing_raised do
116
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['arunit'].except(:database))
117
+
118
+ config = ARTest.connection_config
119
+ ActiveRecord::Base.connection.execute(
120
+ "SELECT #{config['arunit']['database']}.pirates.*, #{config['arunit2']['database']}.courses.* " \
121
+ "FROM #{config['arunit']['database']}.pirates, #{config['arunit2']['database']}.courses"
122
+ )
123
+ end
124
+ ensure
125
+ ActiveRecord::Base.establish_connection 'arunit'
116
126
  end
117
- ensure
118
- ActiveRecord::Base.establish_connection 'arunit'
119
127
  end
120
128
  end
121
- end
122
-
123
- if current_adapter?(:PostgreSQLAdapter)
124
- def test_encoding
125
- assert_not_nil @connection.encoding
126
- end
127
- end
128
129
 
129
- def test_table_alias
130
- def @connection.test_table_alias_length() 10; end
131
- class << @connection
132
- alias_method :old_table_alias_length, :table_alias_length
133
- alias_method :table_alias_length, :test_table_alias_length
134
- end
130
+ def test_table_alias
131
+ def @connection.test_table_alias_length() 10; end
132
+ class << @connection
133
+ alias_method :old_table_alias_length, :table_alias_length
134
+ alias_method :table_alias_length, :test_table_alias_length
135
+ end
135
136
 
136
- assert_equal 'posts', @connection.table_alias_for('posts')
137
- assert_equal 'posts_comm', @connection.table_alias_for('posts_comments')
138
- assert_equal 'dbo_posts', @connection.table_alias_for('dbo.posts')
137
+ assert_equal 'posts', @connection.table_alias_for('posts')
138
+ assert_equal 'posts_comm', @connection.table_alias_for('posts_comments')
139
+ assert_equal 'dbo_posts', @connection.table_alias_for('dbo.posts')
139
140
 
140
- class << @connection
141
- remove_method :table_alias_length
142
- alias_method :table_alias_length, :old_table_alias_length
141
+ class << @connection
142
+ remove_method :table_alias_length
143
+ alias_method :table_alias_length, :old_table_alias_length
144
+ end
143
145
  end
144
- end
145
146
 
146
- # test resetting sequences in odd tables in postgreSQL
147
- if ActiveRecord::Base.connection.respond_to?(:reset_pk_sequence!)
148
- require 'models/movie'
149
- require 'models/subscriber'
147
+ # test resetting sequences in odd tables in postgreSQL
148
+ if ActiveRecord::Base.connection.respond_to?(:reset_pk_sequence!)
149
+ require 'models/movie'
150
+ require 'models/subscriber'
150
151
 
151
- def test_reset_empty_table_with_custom_pk
152
- Movie.delete_all
153
- Movie.connection.reset_pk_sequence! 'movies'
154
- assert_equal 1, Movie.create(:name => 'fight club').id
155
- end
152
+ def test_reset_empty_table_with_custom_pk
153
+ Movie.delete_all
154
+ Movie.connection.reset_pk_sequence! 'movies'
155
+ assert_equal 1, Movie.create(:name => 'fight club').id
156
+ end
156
157
 
157
- if ActiveRecord::Base.connection.adapter_name != "FrontBase"
158
- def test_reset_table_with_non_integer_pk
159
- Subscriber.delete_all
160
- Subscriber.connection.reset_pk_sequence! 'subscribers'
161
- sub = Subscriber.new(:name => 'robert drake')
162
- sub.id = 'bob drake'
163
- assert_nothing_raised { sub.save! }
158
+ if ActiveRecord::Base.connection.adapter_name != "FrontBase"
159
+ def test_reset_table_with_non_integer_pk
160
+ Subscriber.delete_all
161
+ Subscriber.connection.reset_pk_sequence! 'subscribers'
162
+ sub = Subscriber.new(:name => 'robert drake')
163
+ sub.id = 'bob drake'
164
+ assert_nothing_raised { sub.save! }
165
+ end
164
166
  end
165
167
  end
166
- end
167
168
 
168
- def test_uniqueness_violations_are_translated_to_specific_exception
169
- @connection.execute "INSERT INTO subscribers(nick) VALUES('me')"
170
- assert_raises(ActiveRecord::RecordNotUnique) do
169
+ def test_uniqueness_violations_are_translated_to_specific_exception
171
170
  @connection.execute "INSERT INTO subscribers(nick) VALUES('me')"
171
+ assert_raises(ActiveRecord::RecordNotUnique) do
172
+ @connection.execute "INSERT INTO subscribers(nick) VALUES('me')"
173
+ end
172
174
  end
173
- end
174
175
 
175
- def test_foreign_key_violations_are_translated_to_specific_exception
176
- unless @connection.adapter_name == 'SQLite'
177
- assert_raises(ActiveRecord::InvalidForeignKey) do
178
- # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method
179
- if @connection.prefetch_primary_key?
180
- id_value = @connection.next_sequence_value(@connection.default_sequence_name("fk_test_has_fk", "id"))
181
- @connection.execute "INSERT INTO fk_test_has_fk (id, fk_id) VALUES (#{id_value},0)"
182
- else
183
- @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)"
176
+ def test_foreign_key_violations_are_translated_to_specific_exception
177
+ unless @connection.adapter_name == 'SQLite'
178
+ assert_raises(ActiveRecord::InvalidForeignKey) do
179
+ # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method
180
+ if @connection.prefetch_primary_key?
181
+ id_value = @connection.next_sequence_value(@connection.default_sequence_name("fk_test_has_fk", "id"))
182
+ @connection.execute "INSERT INTO fk_test_has_fk (id, fk_id) VALUES (#{id_value},0)"
183
+ else
184
+ @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)"
185
+ end
184
186
  end
185
187
  end
186
188
  end
187
- end
188
-
189
- unless current_adapter?(:IBM_DBAdapter)
190
- def test_add_limit_offset_should_sanitize_sql_injection_for_limit_without_comas
191
- sql_inject = "1 select * from schema"
192
- assert_no_match(/schema/, @connection.add_limit_offset!("", :limit=>sql_inject))
193
- assert_no_match(/schema/, @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7))
194
- end
195
189
 
196
- def test_add_limit_offset_should_sanitize_sql_injection_for_limit_with_comas
197
- sql_inject = "1, 7 procedure help()"
198
- assert_no_match(/procedure/, @connection.add_limit_offset!("", :limit=>sql_inject))
199
- assert_no_match(/procedure/, @connection.add_limit_offset!("", :limit=>sql_inject, :offset=>7))
190
+ def test_disable_referential_integrity
191
+ assert_nothing_raised do
192
+ @connection.disable_referential_integrity do
193
+ # Oracle adapter uses prefetched primary key values from sequence and passes them to connection adapter insert method
194
+ if @connection.prefetch_primary_key?
195
+ id_value = @connection.next_sequence_value(@connection.default_sequence_name("fk_test_has_fk", "id"))
196
+ @connection.execute "INSERT INTO fk_test_has_fk (id, fk_id) VALUES (#{id_value},0)"
197
+ else
198
+ @connection.execute "INSERT INTO fk_test_has_fk (fk_id) VALUES (0)"
199
+ end
200
+ # should deleted created record as otherwise disable_referential_integrity will try to enable contraints after executed block
201
+ # and will fail (at least on Oracle)
202
+ @connection.execute "DELETE FROM fk_test_has_fk"
203
+ end
204
+ end
200
205
  end
201
206
  end
202
207
  end
@@ -13,11 +13,12 @@ require 'models/comment'
13
13
  require 'models/sponsor'
14
14
  require 'models/member'
15
15
  require 'models/essay'
16
+ require 'models/toy'
16
17
 
17
18
  class BelongsToAssociationsTest < ActiveRecord::TestCase
18
19
  fixtures :accounts, :companies, :developers, :projects, :topics,
19
20
  :developers_projects, :computers, :authors, :author_addresses,
20
- :posts, :tags, :taggings, :comments
21
+ :posts, :tags, :taggings, :comments, :sponsors, :members
21
22
 
22
23
  def test_belongs_to
23
24
  Client.find(3).firm.name
@@ -54,11 +55,6 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
54
55
  assert_nothing_raised { account.firm = account.firm }
55
56
  end
56
57
 
57
- def test_triple_equality
58
- assert Client.find(3).firm === Firm
59
- assert Firm === Client.find(3).firm
60
- end
61
-
62
58
  def test_type_mismatch
63
59
  assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = 1 }
64
60
  assert_raise(ActiveRecord::AssociationTypeMismatch) { Account.find(1).firm = Project.find(1) }
@@ -79,23 +75,17 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
79
75
  end
80
76
 
81
77
  def test_eager_loading_with_primary_key
82
- apple = Firm.create("name" => "Apple")
83
- citibank = Client.create("name" => "Citibank", :firm_name => "Apple")
78
+ Firm.create("name" => "Apple")
79
+ Client.create("name" => "Citibank", :firm_name => "Apple")
84
80
  citibank_result = Client.find(:first, :conditions => {:name => "Citibank"}, :include => :firm_with_primary_key)
85
- assert_not_nil citibank_result.instance_variable_get("@firm_with_primary_key")
81
+ assert citibank_result.association_cache.key?(:firm_with_primary_key)
86
82
  end
87
83
 
88
- def test_no_unexpected_aliasing
89
- first_firm = companies(:first_firm)
90
- another_firm = companies(:another_firm)
91
-
92
- citibank = Account.create("credit_limit" => 10)
93
- citibank.firm = first_firm
94
- original_proxy = citibank.firm
95
- citibank.firm = another_firm
96
-
97
- assert_equal first_firm.object_id, original_proxy.target.object_id
98
- assert_equal another_firm.object_id, citibank.firm.target.object_id
84
+ def test_eager_loading_with_primary_key_as_symbol
85
+ Firm.create("name" => "Apple")
86
+ Client.create("name" => "Citibank", :firm_name => "Apple")
87
+ citibank_result = Client.find(:first, :conditions => {:name => "Citibank"}, :include => :firm_with_primary_key_symbols)
88
+ assert citibank_result.association_cache.key?(:firm_with_primary_key_symbols)
99
89
  end
100
90
 
101
91
  def test_creating_the_belonging_object
@@ -130,6 +120,23 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
130
120
  assert_equal apple.name, client.firm_name
131
121
  end
132
122
 
123
+ def test_create!
124
+ client = Client.create!(:name => "Jimmy")
125
+ account = client.create_account!(:credit_limit => 10)
126
+ assert_equal account, client.account
127
+ assert account.persisted?
128
+ client.save
129
+ client.reload
130
+ assert_equal account, client.account
131
+ end
132
+
133
+ def test_failing_create!
134
+ client = Client.create!(:name => "Jimmy")
135
+ assert_raise(ActiveRecord::RecordInvalid) { client.create_account! }
136
+ assert_not_nil client.account
137
+ assert client.account.new_record?
138
+ end
139
+
133
140
  def test_natural_assignment_to_nil
134
141
  client = Client.find(3)
135
142
  client.firm = nil
@@ -156,6 +163,26 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
156
163
  assert_not_nil Company.find(3).firm_with_condition, "Microsoft should have a firm"
157
164
  end
158
165
 
166
+ def test_polymorphic_association_class
167
+ sponsor = Sponsor.new
168
+ assert_nil sponsor.association(:sponsorable).send(:klass)
169
+
170
+ sponsor.sponsorable_type = '' # the column doesn't have to be declared NOT NULL
171
+ assert_nil sponsor.association(:sponsorable).send(:klass)
172
+
173
+ sponsor.sponsorable = Member.new :name => "Bert"
174
+ assert_equal Member, sponsor.association(:sponsorable).send(:klass)
175
+ end
176
+
177
+ def test_with_polymorphic_and_condition
178
+ sponsor = Sponsor.create
179
+ member = Member.create :name => "Bert"
180
+ sponsor.sponsorable = member
181
+
182
+ assert_equal member, sponsor.sponsorable
183
+ assert_nil sponsor.sponsorable_with_conditions
184
+ end
185
+
159
186
  def test_with_select
160
187
  assert_equal Company.find(2).firm_with_select.attributes.size, 1
161
188
  assert_equal Company.find(2, :include => :firm_with_select ).firm_with_select.attributes.size, 1
@@ -172,17 +199,6 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
172
199
  assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply deleted"
173
200
  end
174
201
 
175
- def test_belongs_to_with_primary_key_counter
176
- debate = Topic.create("title" => "debate")
177
- assert_equal 0, debate.send(:read_attribute, "replies_count"), "No replies yet"
178
-
179
- trash = debate.replies_with_primary_key.create("title" => "blah!", "content" => "world around!")
180
- assert_equal 1, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply created"
181
-
182
- trash.destroy
183
- assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count"), "First reply deleted"
184
- end
185
-
186
202
  def test_belongs_to_counter_with_assigning_nil
187
203
  p = Post.find(1)
188
204
  c = Comment.find(1)
@@ -195,16 +211,23 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
195
211
  assert_equal 1, Post.find(p.id).comments.size
196
212
  end
197
213
 
198
- def test_belongs_to_with_primary_key_counter_with_assigning_nil
199
- debate = Topic.create("title" => "debate")
200
- reply = Reply.create("title" => "blah!", "content" => "world around!", "parent_title" => "debate")
214
+ def test_belongs_to_with_primary_key_counter
215
+ debate = Topic.create("title" => "debate")
216
+ debate2 = Topic.create("title" => "debate2")
217
+ reply = Reply.create("title" => "blah!", "content" => "world around!", "parent_title" => "debate")
218
+
219
+ assert_equal 1, debate.reload.replies_count
220
+ assert_equal 0, debate2.reload.replies_count
201
221
 
202
- assert_equal debate.title, reply.parent_title
203
- assert_equal 1, Topic.find(debate.id).send(:read_attribute, "replies_count")
222
+ reply.topic_with_primary_key = debate2
223
+
224
+ assert_equal 0, debate.reload.replies_count
225
+ assert_equal 1, debate2.reload.replies_count
204
226
 
205
227
  reply.topic_with_primary_key = nil
206
228
 
207
- assert_equal 0, Topic.find(debate.id).send(:read_attribute, "replies_count")
229
+ assert_equal 0, debate.reload.replies_count
230
+ assert_equal 0, debate2.reload.replies_count
208
231
  end
209
232
 
210
233
  def test_belongs_to_counter_with_reassigning
@@ -278,6 +301,15 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
278
301
  assert_equal 1, Topic.find(topic.id)[:replies_count]
279
302
  end
280
303
 
304
+ def test_belongs_to_counter_when_update_column
305
+ topic = Topic.create!(:title => "37s")
306
+ topic.replies.create!(:title => "re: 37s", :content => "rails")
307
+ assert_equal 1, Topic.find(topic.id)[:replies_count]
308
+
309
+ topic.update_column(:content, "rails is wonderfull")
310
+ assert_equal 1, Topic.find(topic.id)[:replies_count]
311
+ end
312
+
281
313
  def test_assignment_before_child_saved
282
314
  final_cut = Client.new("name" => "Final Cut")
283
315
  firm = Firm.find(1)
@@ -308,13 +340,27 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
308
340
  assert_equal Firm.find(:first, :order => "id"), c.firm_with_basic_id
309
341
  end
310
342
 
311
- def test_forgetting_the_load_when_foreign_key_enters_late
312
- c = Client.new
313
- assert_nil c.firm_with_basic_id
343
+ def test_setting_foreign_key_after_nil_target_loaded
344
+ client = Client.new
345
+ client.firm_with_basic_id
346
+ client.firm_id = 1
314
347
 
315
- c.firm_id = 1
316
- # sometimes tests on Oracle fail if ORDER BY is not provided therefore add always :order with :first
317
- assert_equal Firm.find(:first, :order => "id"), c.firm_with_basic_id
348
+ assert_equal companies(:first_firm), client.firm_with_basic_id
349
+ end
350
+
351
+ def test_polymorphic_setting_foreign_key_after_nil_target_loaded
352
+ sponsor = Sponsor.new
353
+ sponsor.sponsorable
354
+ sponsor.sponsorable_id = 1
355
+ sponsor.sponsorable_type = "Member"
356
+
357
+ assert_equal members(:groucho), sponsor.sponsorable
358
+ end
359
+
360
+ def test_dont_find_target_when_foreign_key_is_null
361
+ tagging = taggings(:thinking_general)
362
+ queries = assert_sql { tagging.super_tag }
363
+ assert_equal 0, queries.length
318
364
  end
319
365
 
320
366
  def test_field_name_same_as_foreign_key
@@ -416,6 +462,18 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
416
462
  assert_nil sponsor.sponsorable_id
417
463
  end
418
464
 
465
+ def test_assignment_updates_foreign_id_field_for_new_and_saved_records
466
+ client = Client.new
467
+ saved_firm = Firm.create :name => "Saved"
468
+ new_firm = Firm.new
469
+
470
+ client.firm = saved_firm
471
+ assert_equal saved_firm.id, client.client_of
472
+
473
+ client.firm = new_firm
474
+ assert_nil client.client_of
475
+ end
476
+
419
477
  def test_polymorphic_assignment_with_primary_key_updates_foreign_id_field_for_new_and_saved_records
420
478
  essay = Essay.new
421
479
  saved_writer = Author.create(:name => "David")
@@ -483,4 +541,171 @@ class BelongsToAssociationsTest < ActiveRecord::TestCase
483
541
  new_firm = accounts(:signals37).build_firm(:name => 'Apple')
484
542
  assert_equal new_firm.name, "Apple"
485
543
  end
544
+
545
+ def test_reassigning_the_parent_id_updates_the_object
546
+ client = companies(:second_client)
547
+
548
+ client.firm
549
+ client.firm_with_condition
550
+ firm_proxy = client.send(:association_instance_get, :firm)
551
+ firm_with_condition_proxy = client.send(:association_instance_get, :firm_with_condition)
552
+
553
+ assert !firm_proxy.stale_target?
554
+ assert !firm_with_condition_proxy.stale_target?
555
+ assert_equal companies(:first_firm), client.firm
556
+ assert_equal companies(:first_firm), client.firm_with_condition
557
+
558
+ client.client_of = companies(:another_firm).id
559
+
560
+ assert firm_proxy.stale_target?
561
+ assert firm_with_condition_proxy.stale_target?
562
+ assert_equal companies(:another_firm), client.firm
563
+ assert_equal companies(:another_firm), client.firm_with_condition
564
+ end
565
+
566
+ def test_polymorphic_reassignment_of_associated_id_updates_the_object
567
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
568
+
569
+ sponsor.sponsorable
570
+ proxy = sponsor.send(:association_instance_get, :sponsorable)
571
+
572
+ assert !proxy.stale_target?
573
+ assert_equal members(:groucho), sponsor.sponsorable
574
+
575
+ sponsor.sponsorable_id = members(:some_other_guy).id
576
+
577
+ assert proxy.stale_target?
578
+ assert_equal members(:some_other_guy), sponsor.sponsorable
579
+ end
580
+
581
+ def test_polymorphic_reassignment_of_associated_type_updates_the_object
582
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
583
+
584
+ sponsor.sponsorable
585
+ proxy = sponsor.send(:association_instance_get, :sponsorable)
586
+
587
+ assert !proxy.stale_target?
588
+ assert_equal members(:groucho), sponsor.sponsorable
589
+
590
+ sponsor.sponsorable_type = 'Firm'
591
+
592
+ assert proxy.stale_target?
593
+ assert_equal companies(:first_firm), sponsor.sponsorable
594
+ end
595
+
596
+ def test_reloading_association_with_key_change
597
+ client = companies(:second_client)
598
+ firm = client.association(:firm)
599
+
600
+ client.firm = companies(:another_firm)
601
+ firm.reload
602
+ assert_equal companies(:another_firm), firm.target
603
+
604
+ client.client_of = companies(:first_firm).id
605
+ firm.reload
606
+ assert_equal companies(:first_firm), firm.target
607
+ end
608
+
609
+ def test_polymorphic_counter_cache
610
+ tagging = taggings(:welcome_general)
611
+ post = posts(:welcome)
612
+ comment = comments(:greetings)
613
+
614
+ assert_difference lambda { post.reload.taggings_count }, -1 do
615
+ assert_difference 'comment.reload.taggings_count', +1 do
616
+ tagging.taggable = comment
617
+ end
618
+ end
619
+ end
620
+
621
+ def test_polymorphic_with_custom_foreign_type
622
+ sponsor = sponsors(:moustache_club_sponsor_for_groucho)
623
+ groucho = members(:groucho)
624
+ other = members(:some_other_guy)
625
+
626
+ assert_equal groucho, sponsor.sponsorable
627
+ assert_equal groucho, sponsor.thing
628
+
629
+ sponsor.thing = other
630
+
631
+ assert_equal other, sponsor.sponsorable
632
+ assert_equal other, sponsor.thing
633
+
634
+ sponsor.sponsorable = groucho
635
+
636
+ assert_equal groucho, sponsor.sponsorable
637
+ assert_equal groucho, sponsor.thing
638
+ end
639
+
640
+ def test_build_with_conditions
641
+ client = companies(:second_client)
642
+ firm = client.build_bob_firm
643
+
644
+ assert_equal "Bob", firm.name
645
+ end
646
+
647
+ def test_create_with_conditions
648
+ client = companies(:second_client)
649
+ firm = client.create_bob_firm
650
+
651
+ assert_equal "Bob", firm.name
652
+ end
653
+
654
+ def test_create_bang_with_conditions
655
+ client = companies(:second_client)
656
+ firm = client.create_bob_firm!
657
+
658
+ assert_equal "Bob", firm.name
659
+ end
660
+
661
+ def test_build_with_block
662
+ client = Client.create(:name => 'Client Company')
663
+
664
+ firm = client.build_firm{ |f| f.name = 'Agency Company' }
665
+ assert_equal 'Agency Company', firm.name
666
+ end
667
+
668
+ def test_create_with_block
669
+ client = Client.create(:name => 'Client Company')
670
+
671
+ firm = client.create_firm{ |f| f.name = 'Agency Company' }
672
+ assert_equal 'Agency Company', firm.name
673
+ end
674
+
675
+ def test_create_bang_with_block
676
+ client = Client.create(:name => 'Client Company')
677
+
678
+ firm = client.create_firm!{ |f| f.name = 'Agency Company' }
679
+ assert_equal 'Agency Company', firm.name
680
+ end
681
+
682
+ def test_should_set_foreign_key_on_create_association
683
+ client = Client.create! :name => "fuu"
684
+
685
+ firm = client.create_firm :name => "baa"
686
+ assert_equal firm.id, client.client_of
687
+ end
688
+
689
+ def test_should_set_foreign_key_on_create_association!
690
+ client = Client.create! :name => "fuu"
691
+
692
+ firm = client.create_firm! :name => "baa"
693
+ assert_equal firm.id, client.client_of
694
+ end
695
+
696
+ def test_self_referential_belongs_to_with_counter_cache_assigning_nil
697
+ comment = Comment.create! :post => posts(:thinking), :body => "fuu"
698
+ comment.parent = nil
699
+ comment.save!
700
+
701
+ assert_equal nil, comment.reload.parent
702
+ assert_equal 0, comments(:greetings).reload.children_count
703
+ end
704
+
705
+ def test_polymorphic_with_custom_primary_key
706
+ toy = Toy.create!
707
+ sponsor = Sponsor.create!(:sponsorable => toy)
708
+
709
+ assert_equal toy, sponsor.reload.sponsorable
710
+ end
486
711
  end