db2 2.6.2 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
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