activerecord 1.15.2 → 1.15.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activerecord might be problematic. Click here for more details.

Files changed (36) hide show
  1. data/CHANGELOG +11 -0
  2. data/Rakefile +8 -8
  3. data/lib/active_record/associations.rb +61 -44
  4. data/lib/active_record/associations/has_many_through_association.rb +11 -1
  5. data/lib/active_record/base.rb +8 -9
  6. data/lib/active_record/fixtures.rb +18 -6
  7. data/lib/active_record/reflection.rb +6 -2
  8. data/lib/active_record/vendor/mysql.rb +8 -4
  9. data/lib/active_record/version.rb +1 -1
  10. data/test/associations/join_model_test.rb +18 -1
  11. data/test/fixtures/categories_ordered.yml +1 -1
  12. data/test/fixtures/db_definitions/db2.drop.sql +1 -0
  13. data/test/fixtures/db_definitions/db2.sql +5 -0
  14. data/test/fixtures/db_definitions/firebird.drop.sql +2 -0
  15. data/test/fixtures/db_definitions/firebird.sql +7 -0
  16. data/test/fixtures/db_definitions/frontbase.drop.sql +1 -0
  17. data/test/fixtures/db_definitions/frontbase.sql +6 -0
  18. data/test/fixtures/db_definitions/mysql.drop.sql +1 -0
  19. data/test/fixtures/db_definitions/mysql.sql +6 -0
  20. data/test/fixtures/db_definitions/openbase.sql +8 -0
  21. data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
  22. data/test/fixtures/db_definitions/oracle.sql +6 -0
  23. data/test/fixtures/db_definitions/postgresql.drop.sql +1 -0
  24. data/test/fixtures/db_definitions/postgresql.sql +5 -0
  25. data/test/fixtures/db_definitions/sqlite.drop.sql +1 -0
  26. data/test/fixtures/db_definitions/sqlite.sql +5 -0
  27. data/test/fixtures/db_definitions/sqlserver.drop.sql +1 -0
  28. data/test/fixtures/db_definitions/sqlserver.sql +5 -0
  29. data/test/fixtures/db_definitions/sybase.drop.sql +1 -0
  30. data/test/fixtures/db_definitions/sybase.sql +5 -0
  31. data/test/fixtures/mixed_case_monkey.rb +3 -0
  32. data/test/fixtures/mixed_case_monkeys.yml +6 -0
  33. data/test/fixtures/tag.rb +2 -0
  34. data/test/fixtures/vertex.rb +1 -1
  35. data/test/pk_test.rb +24 -1
  36. metadata +6 -4
data/CHANGELOG CHANGED
@@ -1,3 +1,14 @@
1
+ *1.15.3* (March 12th, 2007)
2
+
3
+ * Allow a polymorphic :source for has_many :through associations. Closes #7143 [protocool]
4
+
5
+ * Consistently quote primary key column names. #7763 [toolmantim]
6
+
7
+ * Fixtures: fix YAML ordered map support. #2665 [Manuel Holtgrewe, nfbuckley]
8
+
9
+ * Fix has_many :through << with custom foreign keys. #6466, #7153 [naffis, Rich Collins]
10
+
11
+
1
12
  *1.15.2* (February 5th, 2007)
2
13
 
3
14
  * Pass a range in :conditions to use the SQL BETWEEN operator. #6974 [dcmanges]
data/Rakefile CHANGED
@@ -151,7 +151,7 @@ spec = Gem::Specification.new do |s|
151
151
  s.files = s.files + Dir.glob( "#{dir}/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
152
152
  end
153
153
 
154
- s.add_dependency('activesupport', '= 1.4.1' + PKG_BUILD)
154
+ s.add_dependency('activesupport', '= 1.4.2' + PKG_BUILD)
155
155
 
156
156
  s.files.delete "test/fixtures/fixture_database.sqlite"
157
157
  s.files.delete "test/fixtures/fixture_database_2.sqlite"
@@ -216,11 +216,11 @@ end
216
216
 
217
217
  desc "Publish the release files to RubyForge."
218
218
  task :release => [ :package ] do
219
- `rubyforge login`
219
+ require 'rubyforge'
220
220
 
221
- for ext in %w( gem tgz zip )
222
- release_command = "rubyforge add_release #{PKG_NAME} #{PKG_NAME} 'REL #{PKG_VERSION}' pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}"
223
- puts release_command
224
- system(release_command)
225
- end
226
- end
221
+ packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
222
+
223
+ rubyforge = RubyForge.new
224
+ rubyforge.login
225
+ rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
226
+ end
@@ -20,7 +20,13 @@ module ActiveRecord
20
20
  super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' on the polymorphic object '#{source_reflection.class_name}##{source_reflection.name}'.")
21
21
  end
22
22
  end
23
-
23
+
24
+ class HasManyThroughAssociationPointlessSourceTypeError < ActiveRecordError #:nodoc:
25
+ def initialize(owner_class_name, reflection, source_reflection)
26
+ super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' with a :source_type option if the '#{reflection.through_reflection.class_name}##{source_reflection.name}' is not polymorphic. Try removing :source_type on your association.")
27
+ end
28
+ end
29
+
24
30
  class HasManyThroughSourceAssociationNotFoundError < ActiveRecordError #:nodoc:
25
31
  def initialize(reflection)
26
32
  through_reflection = reflection.through_reflection
@@ -529,6 +535,8 @@ module ActiveRecord
529
535
  # * <tt>:source</tt>: Specifies the source association name used by <tt>has_many :through</tt> queries. Only use it if the name cannot be
530
536
  # inferred from the association. <tt>has_many :subscribers, :through => :subscriptions</tt> will look for either +:subscribers+ or
531
537
  # +:subscriber+ on +Subscription+, unless a +:source+ is given.
538
+ # * <tt>:source_type</tt>: Specifies type of the source association used by <tt>has_many :through</tt> queries where the source association
539
+ # is a polymorphic belongs_to.
532
540
  # * <tt>:uniq</tt> - if set to true, duplicates will be omitted from the collection. Useful in conjunction with :through.
533
541
  #
534
542
  # Option examples:
@@ -1087,7 +1095,7 @@ module ActiveRecord
1087
1095
  :class_name, :table_name, :foreign_key,
1088
1096
  :exclusively_dependent, :dependent,
1089
1097
  :select, :conditions, :include, :order, :group, :limit, :offset,
1090
- :as, :through, :source,
1098
+ :as, :through, :source, :source_type,
1091
1099
  :uniq,
1092
1100
  :finder_sql, :counter_sql,
1093
1101
  :before_add, :after_add, :before_remove, :after_remove,
@@ -1491,57 +1499,65 @@ module ActiveRecord
1491
1499
  case
1492
1500
  when reflection.macro == :has_many && reflection.options[:through]
1493
1501
  through_conditions = through_reflection.options[:conditions] ? "AND #{interpolate_sql(sanitize_sql(through_reflection.options[:conditions]))}" : ''
1502
+
1503
+ jt_foreign_key = jt_as_extra = jt_source_extra = jt_sti_extra = nil
1504
+ first_key = second_key = as_extra = nil
1505
+
1494
1506
  if through_reflection.options[:as] # has_many :through against a polymorphic join
1495
- polymorphic_foreign_key = through_reflection.options[:as].to_s + '_id'
1496
- polymorphic_foreign_type = through_reflection.options[:as].to_s + '_type'
1497
-
1498
- " LEFT OUTER JOIN %s ON (%s.%s = %s.%s AND %s.%s = %s) " % [
1499
- table_alias_for(through_reflection.klass.table_name, aliased_join_table_name),
1500
- aliased_join_table_name, polymorphic_foreign_key,
1501
- parent.aliased_table_name, parent.primary_key,
1502
- aliased_join_table_name, polymorphic_foreign_type, klass.quote_value(parent.active_record.base_class.name)] +
1503
- " LEFT OUTER JOIN %s ON %s.%s = %s.%s " % [table_name_and_alias,
1504
- aliased_table_name, primary_key, aliased_join_table_name, options[:foreign_key] || reflection.klass.to_s.classify.foreign_key
1507
+ jt_foreign_key = through_reflection.options[:as].to_s + '_id'
1508
+ jt_as_extra = " AND %s.%s = %s" % [
1509
+ aliased_join_table_name, reflection.active_record.connection.quote_column_name(through_reflection.options[:as].to_s + '_type'),
1510
+ klass.quote_value(parent.active_record.base_class.name)
1505
1511
  ]
1506
1512
  else
1507
- if source_reflection.macro == :has_many && source_reflection.options[:as]
1508
- " LEFT OUTER JOIN %s ON %s.%s = %s.%s " % [
1509
- table_alias_for(through_reflection.klass.table_name, aliased_join_table_name), aliased_join_table_name,
1510
- through_reflection.primary_key_name,
1511
- parent.aliased_table_name, parent.primary_key] +
1512
- " LEFT OUTER JOIN %s ON %s.%s = %s.%s AND %s.%s = %s " % [
1513
- table_name_and_alias,
1514
- aliased_table_name, "#{source_reflection.options[:as]}_id",
1515
- aliased_join_table_name, options[:foreign_key] || primary_key,
1516
- aliased_table_name, "#{source_reflection.options[:as]}_type",
1513
+ jt_foreign_key = through_reflection.primary_key_name
1514
+ end
1515
+
1516
+ case source_reflection.macro
1517
+ when :has_many
1518
+ if source_reflection.options[:as]
1519
+ first_key = "#{source_reflection.options[:as]}_id"
1520
+ second_key = options[:foreign_key] || primary_key
1521
+ as_extra = " AND %s.%s = %s" % [
1522
+ aliased_table_name, reflection.active_record.connection.quote_column_name("#{source_reflection.options[:as]}_type"),
1517
1523
  klass.quote_value(source_reflection.active_record.base_class.name)
1518
1524
  ]
1519
1525
  else
1520
- case source_reflection.macro
1521
- when :belongs_to
1522
- first_key = primary_key
1523
- second_key = source_reflection.options[:foreign_key] || klass.to_s.classify.foreign_key
1524
- extra = nil
1525
- when :has_many
1526
- first_key = through_reflection.klass.base_class.to_s.classify.foreign_key
1527
- second_key = options[:foreign_key] || primary_key
1528
- extra = through_reflection.klass.descends_from_active_record? ? nil :
1529
- " AND %s.%s = %s" % [
1530
- aliased_join_table_name,
1531
- reflection.active_record.connection.quote_column_name(through_reflection.active_record.inheritance_column),
1532
- through_reflection.klass.quote_value(through_reflection.klass.name.demodulize)]
1533
- end
1534
- " LEFT OUTER JOIN %s ON (%s.%s = %s.%s%s) " % [
1535
- table_alias_for(through_reflection.klass.table_name, aliased_join_table_name),
1536
- aliased_join_table_name, through_reflection.primary_key_name,
1537
- parent.aliased_table_name, parent.primary_key, extra] +
1538
- " LEFT OUTER JOIN %s ON (%s.%s = %s.%s) " % [
1539
- table_name_and_alias,
1540
- aliased_table_name, first_key,
1541
- aliased_join_table_name, second_key
1526
+ first_key = through_reflection.klass.base_class.to_s.classify.foreign_key
1527
+ second_key = options[:foreign_key] || primary_key
1528
+ end
1529
+
1530
+ unless through_reflection.klass.descends_from_active_record?
1531
+ jt_sti_extra = " AND %s.%s = %s" % [
1532
+ aliased_join_table_name,
1533
+ reflection.active_record.connection.quote_column_name(through_reflection.active_record.inheritance_column),
1534
+ through_reflection.klass.quote_value(through_reflection.klass.name.demodulize)]
1535
+ end
1536
+ when :belongs_to
1537
+ first_key = primary_key
1538
+ if reflection.options[:source_type]
1539
+ second_key = source_reflection.association_foreign_key
1540
+ jt_source_extra = " AND %s.%s = %s" % [
1541
+ aliased_join_table_name, reflection.active_record.connection.quote_column_name(reflection.source_reflection.options[:foreign_type]),
1542
+ klass.quote_value(reflection.options[:source_type])
1542
1543
  ]
1544
+ else
1545
+ second_key = source_reflection.options[:foreign_key] || klass.to_s.classify.foreign_key
1543
1546
  end
1544
1547
  end
1548
+
1549
+ " LEFT OUTER JOIN %s ON (%s.%s = %s.%s%s%s%s) " % [
1550
+ table_alias_for(through_reflection.klass.table_name, aliased_join_table_name),
1551
+ parent.aliased_table_name, reflection.active_record.connection.quote_column_name(parent.primary_key),
1552
+ aliased_join_table_name, reflection.active_record.connection.quote_column_name(jt_foreign_key),
1553
+ jt_as_extra, jt_source_extra, jt_sti_extra
1554
+ ] +
1555
+ " LEFT OUTER JOIN %s ON (%s.%s = %s.%s%s) " % [
1556
+ table_name_and_alias,
1557
+ aliased_table_name, reflection.active_record.connection.quote_column_name(first_key),
1558
+ aliased_join_table_name, reflection.active_record.connection.quote_column_name(second_key),
1559
+ as_extra
1560
+ ]
1545
1561
 
1546
1562
  when reflection.macro == :has_many && reflection.options[:as]
1547
1563
  " LEFT OUTER JOIN %s ON %s.%s = %s.%s AND %s.%s = %s" % [
@@ -1588,6 +1604,7 @@ module ActiveRecord
1588
1604
  end
1589
1605
 
1590
1606
  protected
1607
+
1591
1608
  def pluralize(table_name)
1592
1609
  ActiveRecord::Base.pluralize_table_names ? table_name.to_s.pluralize : table_name
1593
1610
  end
@@ -138,7 +138,11 @@ module ActiveRecord
138
138
 
139
139
  # Construct attributes for :through pointing to owner and associate.
140
140
  def construct_join_attributes(associate)
141
- construct_owner_attributes(@reflection.through_reflection).merge(@reflection.source_reflection.association_foreign_key => associate.id)
141
+ returning construct_owner_attributes(@reflection.through_reflection).merge(@reflection.source_reflection.primary_key_name => associate.id) do |join_attributes|
142
+ if @reflection.options[:source_type]
143
+ join_attributes.merge!(@reflection.source_reflection.options[:foreign_type] => associate.class.base_class.name.to_s)
144
+ end
145
+ end
142
146
  end
143
147
 
144
148
  # Associate attributes pointing to owner, quoted.
@@ -176,6 +180,12 @@ module ActiveRecord
176
180
  if @reflection.through_reflection.options[:as] || @reflection.source_reflection.macro == :belongs_to
177
181
  reflection_primary_key = @reflection.klass.primary_key
178
182
  source_primary_key = @reflection.source_reflection.primary_key_name
183
+ if @reflection.options[:source_type]
184
+ polymorphic_join = "AND %s.%s = %s" % [
185
+ @reflection.through_reflection.table_name, "#{@reflection.source_reflection.options[:foreign_type]}",
186
+ @owner.class.quote_value(@reflection.options[:source_type])
187
+ ]
188
+ end
179
189
  else
180
190
  reflection_primary_key = @reflection.source_reflection.primary_key_name
181
191
  source_primary_key = @reflection.klass.primary_key
@@ -479,7 +479,7 @@ module ActiveRecord #:nodoc:
479
479
  # Deletes the record with the given +id+ without instantiating an object first. If an array of ids is provided, all of them
480
480
  # are deleted.
481
481
  def delete(id)
482
- delete_all([ "#{primary_key} IN (?)", id ])
482
+ delete_all([ "#{connection.quote_column_name(primary_key)} IN (?)", id ])
483
483
  end
484
484
 
485
485
  # Destroys the record with the given +id+ by instantiating the object and calling #destroy (all the callbacks are the triggered).
@@ -526,12 +526,12 @@ module ActiveRecord #:nodoc:
526
526
  # for looping over a collection where each element require a number of aggregate values. Like the DiscussionBoard
527
527
  # that needs to list both the number of posts and comments.
528
528
  def increment_counter(counter_name, id)
529
- update_all "#{counter_name} = #{counter_name} + 1", "#{primary_key} = #{quote_value(id)}"
529
+ update_all "#{connection.quote_column_name(counter_name)} = #{connection.quote_column_name(counter_name)} + 1", "#{connection.quote_column_name(primary_key)} = #{quote_value(id)}"
530
530
  end
531
531
 
532
532
  # Works like increment_counter, but decrements instead.
533
533
  def decrement_counter(counter_name, id)
534
- update_all "#{counter_name} = #{counter_name} - 1", "#{primary_key} = #{quote_value(id)}"
534
+ update_all "#{connection.quote_column_name(counter_name)} = #{connection.quote_column_name(counter_name)} - 1", "#{connection.quote_column_name(primary_key)} = #{quote_value(id)}"
535
535
  end
536
536
 
537
537
 
@@ -1020,7 +1020,7 @@ module ActiveRecord #:nodoc:
1020
1020
 
1021
1021
  def find_one(id, options)
1022
1022
  conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
1023
- options.update :conditions => "#{table_name}.#{primary_key} = #{quote_value(id,columns_hash[primary_key])}#{conditions}"
1023
+ options.update :conditions => "#{table_name}.#{connection.quote_column_name(primary_key)} = #{quote_value(id,columns_hash[primary_key])}#{conditions}"
1024
1024
 
1025
1025
  # Use find_every(options).first since the primary key condition
1026
1026
  # already ensures we have a single record. Using find_initial adds
@@ -1035,7 +1035,7 @@ module ActiveRecord #:nodoc:
1035
1035
  def find_some(ids, options)
1036
1036
  conditions = " AND (#{sanitize_sql(options[:conditions])})" if options[:conditions]
1037
1037
  ids_list = ids.map { |id| quote_value(id,columns_hash[primary_key]) }.join(',')
1038
- options.update :conditions => "#{table_name}.#{primary_key} IN (#{ids_list})#{conditions}"
1038
+ options.update :conditions => "#{table_name}.#{connection.quote_column_name(primary_key)} IN (#{ids_list})#{conditions}"
1039
1039
 
1040
1040
  result = find_every(options)
1041
1041
 
@@ -1052,10 +1052,9 @@ module ActiveRecord #:nodoc:
1052
1052
  def instantiate(record)
1053
1053
  object =
1054
1054
  if subclass_name = record[inheritance_column]
1055
- # No type given.
1056
1055
  if subclass_name.empty?
1056
+ # No type given.
1057
1057
  allocate
1058
-
1059
1058
  else
1060
1059
  # Ignore type if no column is present since it was probably
1061
1060
  # pulled in from a sloppy join.
@@ -1558,7 +1557,7 @@ module ActiveRecord #:nodoc:
1558
1557
  unless new_record?
1559
1558
  connection.delete <<-end_sql, "#{self.class.name} Destroy"
1560
1559
  DELETE FROM #{self.class.table_name}
1561
- WHERE #{self.class.primary_key} = #{quoted_id}
1560
+ WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quoted_id}
1562
1561
  end_sql
1563
1562
  end
1564
1563
 
@@ -1797,7 +1796,7 @@ module ActiveRecord #:nodoc:
1797
1796
  connection.update(
1798
1797
  "UPDATE #{self.class.table_name} " +
1799
1798
  "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false))} " +
1800
- "WHERE #{self.class.primary_key} = #{quote_value(id)}",
1799
+ "WHERE #{connection.quote_column_name(self.class.primary_key)} = #{quote_value(id)}",
1801
1800
  "#{self.class.name} Update"
1802
1801
  )
1803
1802
  end
@@ -301,18 +301,30 @@ class Fixtures < YAML::Omap
301
301
  yaml_string << IO.read(subfixture_path)
302
302
  end
303
303
  yaml_string << IO.read(yaml_file_path)
304
+
304
305
  begin
305
306
  yaml = YAML::load(erb_render(yaml_string))
306
307
  rescue Exception=>boom
307
308
  raise Fixture::FormatError, "a YAML error occurred parsing #{yaml_file_path}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{boom.class}: #{boom}"
308
- end
309
+ end
310
+
309
311
  if yaml
310
- yaml = yaml.value if yaml.respond_to?(:type_id) and yaml.respond_to?(:value)
311
- yaml.each do |name, data|
312
- unless data
313
- raise Fixture::FormatError, "Bad data for #{@class_name} fixture named #{name} (nil)"
312
+ # If the file is an ordered map, extract its children.
313
+ yaml_value =
314
+ if yaml.respond_to?(:type_id) && yaml.respond_to?(:value)
315
+ yaml.value
316
+ else
317
+ [yaml]
318
+ end
319
+
320
+ yaml_value.each do |fixture|
321
+ fixture.each do |name, data|
322
+ unless data
323
+ raise Fixture::FormatError, "Bad data for #{@class_name} fixture named #{name} (nil)"
324
+ end
325
+
326
+ self[name] = Fixture.new(data, @class_name)
314
327
  end
315
- self[name] = Fixture.new(data, @class_name)
316
328
  end
317
329
  end
318
330
  elsif File.file?(csv_file_path)
@@ -186,8 +186,12 @@ module ActiveRecord
186
186
  if source_reflection.nil?
187
187
  raise HasManyThroughSourceAssociationNotFoundError.new(self)
188
188
  end
189
+
190
+ if options[:source_type] && source_reflection.options[:polymorphic].nil?
191
+ raise HasManyThroughAssociationPointlessSourceTypeError.new(active_record.name, self, source_reflection)
192
+ end
189
193
 
190
- if source_reflection.options[:polymorphic]
194
+ if source_reflection.options[:polymorphic] && options[:source_type].nil?
191
195
  raise HasManyThroughAssociationPolymorphicError.new(active_record.name, self, source_reflection)
192
196
  end
193
197
 
@@ -205,7 +209,7 @@ module ActiveRecord
205
209
  if options[:class_name]
206
210
  options[:class_name]
207
211
  elsif through_reflection # get the class_name of the belongs_to association of the through reflection
208
- source_reflection.class_name
212
+ options[:source_type] || source_reflection.class_name
209
213
  else
210
214
  class_name = name.to_s.camelize
211
215
  class_name = class_name.singularize if [ :has_many, :has_and_belongs_to_many ].include?(macro)
@@ -563,9 +563,9 @@ class Mysql
563
563
  def scramble41(password, message)
564
564
  return 0x00.chr if password.nil? or password.empty?
565
565
  buf = [0x14]
566
- s1 = Digest::SHA1.new(password).digest
567
- s2 = Digest::SHA1.new(s1).digest
568
- x = Digest::SHA1.new(message + s2).digest
566
+ s1 = Digest::SHA1.digest(password)
567
+ s2 = Digest::SHA1.digest(s1)
568
+ x = Digest::SHA1.digest(message + s2)
569
569
  (0..s1.length - 1).each {|i| buf.push(s1[i] ^ x[i])}
570
570
  buf.pack("C*")
571
571
  end
@@ -1174,7 +1174,11 @@ class << Mysql
1174
1174
  def finalizer(net)
1175
1175
  proc {
1176
1176
  net.clear
1177
- net.write Mysql::COM_QUIT.chr
1177
+ begin
1178
+ net.write(Mysql::COM_QUIT.chr)
1179
+ net.close
1180
+ rescue # Ignore IOError if socket is already closed.
1181
+ end
1178
1182
  }
1179
1183
  end
1180
1184
 
@@ -2,7 +2,7 @@ module ActiveRecord
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 1
4
4
  MINOR = 15
5
- TINY = 2
5
+ TINY = 3
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -6,10 +6,12 @@ require 'fixtures/comment'
6
6
  require 'fixtures/author'
7
7
  require 'fixtures/category'
8
8
  require 'fixtures/categorization'
9
+ require 'fixtures/vertex'
10
+ require 'fixtures/edge'
9
11
 
10
12
  class AssociationsJoinModelTest < Test::Unit::TestCase
11
13
  self.use_transactional_fixtures = false
12
- fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites
14
+ fixtures :posts, :authors, :categories, :categorizations, :comments, :tags, :taggings, :author_favorites, :vertices
13
15
 
14
16
  def test_has_many
15
17
  assert authors(:david).categories.include?(categories(:general))
@@ -298,6 +300,18 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
298
300
  assert_equal [posts(:welcome), posts(:thinking)], tags(:general).taggings.find(:all, :include => :taggable)
299
301
  end
300
302
  end
303
+
304
+ def test_has_many_polymorphic_with_source_type
305
+ assert_equal [posts(:welcome), posts(:thinking)], tags(:general).tagged_posts
306
+ end
307
+
308
+ def test_eager_has_many_polymorphic_with_source_type
309
+ tag_with_include = Tag.find(tags(:general).id, :include => :tagged_posts)
310
+ desired = [posts(:welcome), posts(:thinking)]
311
+ assert_no_queries do
312
+ assert_equal desired, tag_with_include.tagged_posts
313
+ end
314
+ end
301
315
 
302
316
  def test_has_many_through_has_many_find_all
303
317
  assert_equal comments(:greetings), authors(:david).comments.find(:all, :order => 'comments.id').first
@@ -414,6 +428,9 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
414
428
  message = "Expected a Tagging in taggings collection, got #{wrong.class}.")
415
429
  assert_equal(count + 4, post_thinking.tags.size)
416
430
  assert_equal(count + 4, post_thinking.tags(true).size)
431
+
432
+ # Raises if the wrong reflection name is used to set the Edge belongs_to
433
+ assert_nothing_raised { vertices(:vertex_1).sinks << vertices(:vertex_5) }
417
434
  end
418
435
 
419
436
  def test_adding_junk_to_has_many_through_should_raise_type_mismatch
@@ -1,4 +1,4 @@
1
- --- !omap
1
+ --- !!omap
2
2
  <% 100.times do |i| %>
3
3
  - fixture_no_<%= i %>:
4
4
  id: <%= i %>
@@ -29,3 +29,4 @@ DROP TABLE fk_test_has_fk;
29
29
  DROP TABLE keyboards;
30
30
  DROP TABLE legacy_things;
31
31
  DROP TABLE numeric_data;
32
+ DROP TABLE mixed_case_monkeys;
@@ -224,3 +224,8 @@ CREATE TABLE numeric_data (
224
224
  my_house_population DECIMAL(2),
225
225
  decimal_number_with_default DECIMAL(3,2) DEFAULT 2.78
226
226
  );
227
+
228
+ CREATE TABLE mixed_case_monkeys (
229
+ monkeyID INT NOT NULL PRIMARY KEY,
230
+ fleaCount INT
231
+ );
@@ -30,6 +30,7 @@ DROP TABLE keyboards;
30
30
  DROP TABLE defaults;
31
31
  DROP TABLE legacy_things;
32
32
  DROP TABLE numeric_data;
33
+ DROP TABLE mixed_case_monkeys;
33
34
 
34
35
  DROP DOMAIN D_BOOLEAN;
35
36
 
@@ -59,3 +60,4 @@ DROP GENERATOR keyboards_seq;
59
60
  DROP GENERATOR defaults_seq;
60
61
  DROP GENERATOR legacy_things_seq;
61
62
  DROP GENERATOR numeric_data_seq;
63
+ DROP GENERATOR mixed_case_monkeys_seq;
@@ -295,3 +295,10 @@ CREATE TABLE numeric_data (
295
295
  );
296
296
  CREATE GENERATOR numeric_data_seq;
297
297
  SET GENERATOR numeric_data_seq TO 10000;
298
+
299
+ CREATE TABLE mixed_case_monkeys (
300
+ "monkeyID" BIGINT NOT NULL,
301
+ "fleaCount" INTEGER
302
+ );
303
+ CREATE GENERATOR mixed_case_monkeys_seq;
304
+ SET GENERATOR mixed_case_monkeys_seq TO 10000;
@@ -29,3 +29,4 @@ DROP TABLE fk_test_has_pk CASCADE;
29
29
  DROP TABLE keyboards CASCADE;
30
30
  DROP TABLE legacy_things CASCADE;
31
31
  DROP TABLE numeric_data CASCADE;
32
+ DROP TABLE mixed_case_monkeys CASCADE;
@@ -260,3 +260,9 @@ CREATE TABLE "numeric_data" (
260
260
  primary key ("id")
261
261
  );
262
262
  SET UNIQUE FOR numeric_data(id);
263
+
264
+ CREATE TABLE mixed_case_monkeys (
265
+ "monkeyID" integer DEFAULT unique,
266
+ "fleaCount" integer
267
+ );
268
+ SET UNIQUE FOR mixed_case_monkeys("monkeyID");
@@ -29,3 +29,4 @@ DROP TABLE fk_test_has_pk;
29
29
  DROP TABLE keyboards;
30
30
  DROP TABLE legacy_things;
31
31
  DROP TABLE numeric_data;
32
+ DROP TABLE mixed_case_monkeys;
@@ -226,3 +226,9 @@ CREATE TABLE `numeric_data` (
226
226
  `my_house_population` decimal(2),
227
227
  `decimal_number_with_default` decimal(3,2) DEFAULT 2.78
228
228
  ) TYPE=InnoDB;
229
+
230
+ CREATE TABLE mixed_case_monkeys (
231
+ `monkeyID` int(11) NOT NULL auto_increment,
232
+ `fleaCount` int(11),
233
+ PRIMARY KEY (`monkeyID`)
234
+ ) TYPE=InnoDB;
@@ -292,3 +292,11 @@ CREATE TABLE numeric_data (
292
292
  go
293
293
  CREATE PRIMARY KEY numeric_data (id)
294
294
  go
295
+
296
+ CREATE TABLE mixed_case_monkeys (
297
+ monkeyID INTEGER NOT NULL DEFAULT _rowid,
298
+ fleaCount INTEGER
299
+ );
300
+ go
301
+ CREATE PRIMARY KEY mixed_case_monkeys (monkeyID)
302
+ go
@@ -30,6 +30,7 @@ drop table fk_test_has_fk;
30
30
  drop table keyboards;
31
31
  drop table legacy_things;
32
32
  drop table numeric_data;
33
+ drop table mixed_case_monkeys;
33
34
 
34
35
  drop sequence accounts_seq;
35
36
  drop sequence funny_jokes_seq;
@@ -61,3 +62,4 @@ drop sequence fk_test_has_fk_seq;
61
62
  drop sequence keyboards_seq;
62
63
  drop sequence legacy_things_seq;
63
64
  drop sequence numeric_data_seq;
65
+ drop sequence mixed_case_monkeys_seq;
@@ -317,3 +317,9 @@ CREATE TABLE numeric_data (
317
317
  decimal_number_with_default decimal(3,2) DEFAULT 2.78
318
318
  );
319
319
  create sequence numeric_data_seq minvalue 10000;
320
+
321
+ CREATE TABLE mixed_case_monkeys (
322
+ "monkeyID" INTEGER NOT NULL PRIMARY KEY,
323
+ "fleaCount" INTEGER
324
+ );
325
+ create sequence mixed_case_monkeys_seq minvalue 10000;
@@ -34,3 +34,4 @@ DROP TABLE keyboards;
34
34
  DROP TABLE legacy_things;
35
35
  DROP TABLE numeric_data;
36
36
  DROP TABLE column_data;
37
+ DROP TABLE mixed_case_monkeys;
@@ -256,3 +256,8 @@ CREATE TABLE numeric_data (
256
256
  my_house_population decimal(2),
257
257
  decimal_number_with_default decimal(3,2) default 2.78
258
258
  );
259
+
260
+ CREATE TABLE mixed_case_monkeys (
261
+ "monkeyID" INTEGER PRIMARY KEY,
262
+ "fleaCount" INTEGER
263
+ );
@@ -29,3 +29,4 @@ DROP TABLE fk_test_has_pk;
29
29
  DROP TABLE keyboards;
30
30
  DROP TABLE legacy_things;
31
31
  DROP TABLE numeric_data;
32
+ DROP TABLE mixed_case_monkeys;
@@ -208,3 +208,8 @@ CREATE TABLE 'numeric_data' (
208
208
  'my_house_population' DECIMAL(2),
209
209
  'decimal_number_with_default' DECIMAL(3,2) DEFAULT 2.78
210
210
  );
211
+
212
+ CREATE TABLE mixed_case_monkeys (
213
+ 'monkeyID' INTEGER NOT NULL PRIMARY KEY,
214
+ 'fleaCount' INTEGER
215
+ );
@@ -31,3 +31,4 @@ DROP TABLE keyboards;
31
31
  DROP TABLE legacy_things;
32
32
  DROP TABLE numeric_data;
33
33
  DROP TABLE [order];
34
+ DROP TABLE mixed_case_monkeys;
@@ -236,3 +236,8 @@ CREATE TABLE [order] (
236
236
  texture varchar(255),
237
237
  flavor varchar(255)
238
238
  );
239
+
240
+ CREATE TABLE mixed_case_monkeys (
241
+ [monkeyID] int NOT NULL IDENTITY(1, 1),
242
+ [fleaCount] int default NULL
243
+ );
@@ -29,5 +29,6 @@ DROP TABLE fk_test_has_pk
29
29
  DROP TABLE keyboards
30
30
  DROP TABLE legacy_things
31
31
  DROP TABLE numeric_data
32
+ DROP TABLE mixed_case_monkeys
32
33
  DROP TABLE schema_info
33
34
  go
@@ -210,4 +210,9 @@ CREATE TABLE numeric_data (
210
210
  decimal_number_with_default numeric(3,2) DEFAULT 2.78
211
211
  )
212
212
 
213
+ CREATE TABLE mixed_case_monkeys (
214
+ [monkeyID] numeric(9,0) IDENTITY PRIMARY KEY,
215
+ [fleaCount] numeric(9,0)
216
+ );
217
+
213
218
  go
@@ -0,0 +1,3 @@
1
+ class MixedCaseMonkey < ActiveRecord::Base
2
+ set_primary_key 'monkeyID'
3
+ end
@@ -0,0 +1,6 @@
1
+ first:
2
+ monkeyID: 1
3
+ fleaCount: 42
4
+ second:
5
+ monkeyID: 2
6
+ fleaCount: 43
@@ -2,4 +2,6 @@ class Tag < ActiveRecord::Base
2
2
  has_many :taggings
3
3
  has_many :taggables, :through => :taggings
4
4
  has_one :tagging
5
+
6
+ has_many :tagged_posts, :through => :taggings, :source => :taggable, :source_type => 'Post'
5
7
  end
@@ -1,7 +1,7 @@
1
1
  # This class models a vertex in a directed graph.
2
2
  class Vertex < ActiveRecord::Base
3
3
  has_many :sink_edges, :class_name => 'Edge', :foreign_key => 'source_id'
4
- has_many :sinks, :through => :sink_edges, :source => :sink
4
+ has_many :sinks, :through => :sink_edges
5
5
 
6
6
  has_and_belongs_to_many :sources,
7
7
  :class_name => 'Vertex', :join_table => 'edges',
@@ -4,9 +4,10 @@ require 'fixtures/reply'
4
4
  require 'fixtures/subscriber'
5
5
  require 'fixtures/movie'
6
6
  require 'fixtures/keyboard'
7
+ require 'fixtures/mixed_case_monkey'
7
8
 
8
9
  class PrimaryKeysTest < Test::Unit::TestCase
9
- fixtures :topics, :subscribers, :movies
10
+ fixtures :topics, :subscribers, :movies, :mixed_case_monkeys
10
11
 
11
12
  def test_integer_key
12
13
  topic = Topic.find(1)
@@ -78,4 +79,26 @@ class PrimaryKeysTest < Test::Unit::TestCase
78
79
  Topic.reset_primary_key
79
80
  assert_equal "id", Topic.primary_key
80
81
  end
82
+
83
+ def test_delete_should_quote_pkey
84
+ assert_nothing_raised { MixedCaseMonkey.delete(1) }
85
+ end
86
+ def test_increment_counter_should_quote_pkey_and_quote_counter_columns
87
+ assert_nothing_raised { MixedCaseMonkey.increment_counter(:fleaCount, 1) }
88
+ end
89
+ def test_decrement_counter_should_quote_pkey_and_quote_counter_columns
90
+ assert_nothing_raised { MixedCaseMonkey.decrement_counter(:fleaCount, 1) }
91
+ end
92
+ def test_find_with_one_id_should_quote_pkey
93
+ assert_nothing_raised { MixedCaseMonkey.find(1) }
94
+ end
95
+ def test_find_with_multiple_ids_should_quote_pkey
96
+ assert_nothing_raised { MixedCaseMonkey.find([1,2]) }
97
+ end
98
+ def test_instance_update_should_quote_pkey
99
+ assert_nothing_raised { MixedCaseMonkey.find(1).save }
100
+ end
101
+ def test_instance_destry_should_quote_pkey
102
+ assert_nothing_raised { MixedCaseMonkey.find(1).destroy }
103
+ end
81
104
  end
metadata CHANGED
@@ -1,10 +1,10 @@
1
1
  --- !ruby/object:Gem::Specification
2
- rubygems_version: 0.9.0
2
+ rubygems_version: 0.9.2
3
3
  specification_version: 1
4
4
  name: activerecord
5
5
  version: !ruby/object:Gem::Version
6
- version: 1.15.2
7
- date: 2007-02-05 00:00:00 -06:00
6
+ version: 1.15.3
7
+ date: 2007-03-13 00:00:00 -05:00
8
8
  summary: Implements the ActiveRecord pattern for ORM.
9
9
  require_paths:
10
10
  - lib
@@ -228,6 +228,8 @@ files:
228
228
  - test/fixtures/migrations_with_decimal
229
229
  - test/fixtures/migrations_with_duplicate
230
230
  - test/fixtures/migrations_with_missing_versions
231
+ - test/fixtures/mixed_case_monkey.rb
232
+ - test/fixtures/mixed_case_monkeys.yml
231
233
  - test/fixtures/mixin.rb
232
234
  - test/fixtures/mixins.yml
233
235
  - test/fixtures/movie.rb
@@ -353,5 +355,5 @@ dependencies:
353
355
  requirements:
354
356
  - - "="
355
357
  - !ruby/object:Gem::Version
356
- version: 1.4.1
358
+ version: 1.4.2
357
359
  version: