activerecord 2.3.8 → 2.3.9.pre

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 (64) hide show
  1. data/CHANGELOG +1 -4
  2. data/Rakefile +1 -1
  3. data/examples/performance.rb +2 -0
  4. data/lib/active_record/association_preload.rb +12 -2
  5. data/lib/active_record/associations.rb +1 -1
  6. data/lib/active_record/associations/association_collection.rb +33 -4
  7. data/lib/active_record/attribute_methods.rb +0 -4
  8. data/lib/active_record/autosave_association.rb +2 -2
  9. data/lib/active_record/base.rb +28 -16
  10. data/lib/active_record/connection_adapters/abstract/connection_specification.rb +1 -1
  11. data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1 -0
  12. data/lib/active_record/connection_adapters/abstract_adapter.rb +6 -0
  13. data/lib/active_record/connection_adapters/mysql_adapter.rb +2 -0
  14. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
  15. data/lib/active_record/connection_adapters/sqlite_adapter.rb +2 -1
  16. data/lib/active_record/dirty.rb +1 -1
  17. data/lib/active_record/locale/en.yml +11 -11
  18. data/lib/active_record/locking/optimistic.rb +1 -0
  19. data/lib/active_record/migration.rb +1 -1
  20. data/lib/active_record/named_scope.rb +14 -9
  21. data/lib/active_record/nested_attributes.rb +11 -8
  22. data/lib/active_record/serialization.rb +1 -1
  23. data/lib/active_record/session_store.rb +9 -1
  24. data/lib/active_record/validations.rb +12 -12
  25. data/lib/active_record/version.rb +1 -1
  26. data/test/cases/adapter_test.rb +7 -8
  27. data/test/cases/associations/eager_load_nested_include_test.rb +7 -7
  28. data/test/cases/associations/eager_load_nested_polymorphic_include.rb +19 -0
  29. data/test/cases/associations/eager_test.rb +7 -0
  30. data/test/cases/associations/has_many_associations_test.rb +68 -3
  31. data/test/cases/associations_test.rb +29 -0
  32. data/test/cases/base_test.rb +35 -75
  33. data/test/cases/connection_test_mysql.rb +1 -0
  34. data/test/cases/counter_cache_test.rb +84 -0
  35. data/test/cases/locking_test.rb +2 -1
  36. data/test/cases/migration_test.rb +4 -0
  37. data/test/cases/named_scope_test.rb +6 -1
  38. data/test/cases/nested_attributes_test.rb +49 -14
  39. data/test/cases/reflection_test.rb +5 -5
  40. data/test/cases/sp_test_mysql.rb +16 -0
  41. data/test/cases/transactions_test.rb +22 -1
  42. data/test/cases/validations_i18n_test.rb +12 -12
  43. data/test/cases/validations_test.rb +42 -30
  44. data/test/fixtures/fixture_database.sqlite3 +0 -0
  45. data/test/fixtures/fixture_database_2.sqlite3 +0 -0
  46. data/test/fixtures/polymorphic_designs.yml +19 -0
  47. data/test/fixtures/polymorphic_prices.yml +19 -0
  48. data/test/fixtures/tees.yml +4 -0
  49. data/test/fixtures/ties.yml +4 -0
  50. data/test/models/author.rb +2 -0
  51. data/test/models/event_author.rb +3 -0
  52. data/test/models/pirate.rb +2 -2
  53. data/test/models/polymorphic_design.rb +3 -0
  54. data/test/models/polymorphic_price.rb +3 -0
  55. data/test/models/post.rb +2 -0
  56. data/test/models/tee.rb +4 -0
  57. data/test/models/tie.rb +4 -0
  58. data/test/schema/mysql_specific_schema.rb +7 -0
  59. data/test/schema/schema.rb +16 -0
  60. metadata +24 -13
  61. data/examples/performance.sql +0 -85
  62. data/test/cases/encoding_test.rb +0 -6
  63. data/test/fixtures/fixture_database.sqlite +0 -0
  64. data/test/fixtures/fixture_database_2.sqlite +0 -0
@@ -286,7 +286,9 @@ module ActiveRecord
286
286
  assign_to_or_mark_for_destruction(record, attributes, options[:allow_destroy])
287
287
 
288
288
  elsif attributes['id']
289
- raise_nested_attributes_record_not_found(association_name, attributes['id'])
289
+ existing_record = self.class.reflect_on_association(association_name).klass.find(attributes['id'])
290
+ assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
291
+ self.send(association_name.to_s+'=', existing_record)
290
292
 
291
293
  elsif !reject_new_record?(association_name, attributes)
292
294
  method = "build_#{association_name}"
@@ -356,11 +358,16 @@ module ActiveRecord
356
358
  unless reject_new_record?(association_name, attributes)
357
359
  association.build(attributes.except(*UNASSIGNABLE_KEYS))
358
360
  end
361
+
362
+ elsif existing_records.size == 0 # Existing record but not yet associated
363
+ existing_record = self.class.reflect_on_association(association_name).klass.find(attributes['id'])
364
+ association.send(:add_record_to_target_with_callbacks, existing_record) unless association.loaded?
365
+ assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
366
+
359
367
  elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes['id'].to_s }
360
368
  association.send(:add_record_to_target_with_callbacks, existing_record) unless association.loaded?
361
369
  assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy])
362
- else
363
- raise_nested_attributes_record_not_found(association_name, attributes['id'])
370
+
364
371
  end
365
372
  end
366
373
  end
@@ -380,7 +387,7 @@ module ActiveRecord
380
387
  ConnectionAdapters::Column.value_to_boolean(hash['_destroy'])
381
388
  end
382
389
 
383
- # Determines if a new record should be build by checking for
390
+ # Determines if a new record should be built by checking for
384
391
  # has_destroy_flag? or if a <tt>:reject_if</tt> proc exists for this
385
392
  # association and evaluates to +true+.
386
393
  def reject_new_record?(association_name, attributes)
@@ -396,9 +403,5 @@ module ActiveRecord
396
403
  end
397
404
  end
398
405
 
399
- def raise_nested_attributes_record_not_found(association_name, record_id)
400
- reflection = self.class.reflect_on_association(association_name)
401
- raise RecordNotFound, "Couldn't find #{reflection.klass.name} with ID=#{record_id} for #{self.class.name} with ID=#{id}"
402
- end
403
406
  end
404
407
  end
@@ -74,7 +74,7 @@ module ActiveRecord #:nodoc:
74
74
  end
75
75
 
76
76
  def serializable_record
77
- returning(serializable_record = {}) do
77
+ {}.tap do |serializable_record|
78
78
  serializable_names.each { |name| serializable_record[name] = @record.send(name) }
79
79
  add_includes do |association, records, opts|
80
80
  if records.is_a?(Enumerable)
@@ -184,7 +184,7 @@ module ActiveRecord
184
184
 
185
185
  # Look up a session by id and unmarshal its data if found.
186
186
  def find_by_session_id(session_id)
187
- if record = @@connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{@@connection.quote(session_id)}")
187
+ if record = connection.select_one("SELECT * FROM #{@@table_name} WHERE #{@@session_id_column}=#{connection.quote(session_id)}")
188
188
  new(:session_id => session_id, :marshaled_data => record['data'])
189
189
  end
190
190
  end
@@ -310,6 +310,14 @@ module ActiveRecord
310
310
  return true
311
311
  end
312
312
 
313
+ def destroy(env)
314
+ if sid = current_session_id(env)
315
+ Base.silence do
316
+ get_session_model(env, sid).destroy
317
+ end
318
+ end
319
+ end
320
+
313
321
  def get_session_model(env, sid)
314
322
  if env[ENV_SESSION_OPTIONS_KEY][:id].nil?
315
323
  env[SESSION_RECORD_KEY] = find_session(sid)
@@ -80,7 +80,7 @@ module ActiveRecord
80
80
 
81
81
  # Wraps an error message into a full_message format.
82
82
  #
83
- # The default full_message format for any locale is <tt>"{{attribute}} {{message}}"</tt>.
83
+ # The default full_message format for any locale is <tt>"%{attribute} %{message}"</tt>.
84
84
  # One can specify locale specific default full_message format by storing it as a
85
85
  # translation for the key <tt>:"activerecord.errors.full_messages.format"</tt>.
86
86
  #
@@ -109,7 +109,7 @@ module ActiveRecord
109
109
  keys = [
110
110
  :"full_messages.#{@message}",
111
111
  :'full_messages.format',
112
- '{{attribute}} {{message}}'
112
+ '%{attribute} %{message}'
113
113
  ]
114
114
 
115
115
  options.merge!(:default => keys, :message => self.message)
@@ -604,13 +604,13 @@ module ActiveRecord
604
604
  #
605
605
  # class Person < ActiveRecord::Base
606
606
  # validates_length_of :first_name, :maximum=>30
607
- # validates_length_of :last_name, :maximum=>30, :message=>"less than {{count}} if you don't mind"
607
+ # validates_length_of :last_name, :maximum=>30, :message=>"less than %{count} if you don't mind"
608
608
  # validates_length_of :fax, :in => 7..32, :allow_nil => true
609
609
  # validates_length_of :phone, :in => 7..32, :allow_blank => true
610
610
  # validates_length_of :user_name, :within => 6..20, :too_long => "pick a shorter name", :too_short => "pick a longer name"
611
- # validates_length_of :fav_bra_size, :minimum => 1, :too_short => "please enter at least {{count}} character"
612
- # validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with {{count}} characters... don't play me."
613
- # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least {{count}} words."), :tokenizer => lambda {|str| str.scan(/\w+/) }
611
+ # validates_length_of :fav_bra_size, :minimum => 1, :too_short => "please enter at least %{count} character"
612
+ # validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with %{count} characters... don't play me."
613
+ # validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least %{count} words."), :tokenizer => lambda {|str| str.scan(/\w+/) }
614
614
  # end
615
615
  #
616
616
  # Configuration options:
@@ -621,9 +621,9 @@ module ActiveRecord
621
621
  # * <tt>:in</tt> - A synonym(or alias) for <tt>:within</tt>.
622
622
  # * <tt>:allow_nil</tt> - Attribute may be +nil+; skip validation.
623
623
  # * <tt>:allow_blank</tt> - Attribute may be blank; skip validation.
624
- # * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is {{count}} characters)").
625
- # * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is {{count}} characters)").
626
- # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be {{count}} characters)").
624
+ # * <tt>:too_long</tt> - The error message if the attribute goes over the maximum (default is: "is too long (maximum is %{count} characters)").
625
+ # * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is %{count} characters)").
626
+ # * <tt>:wrong_length</tt> - The error message if using the <tt>:is</tt> method and the attribute is the wrong size (default is: "is the wrong length (should be %{count} characters)").
627
627
  # * <tt>:message</tt> - The error message to use for a <tt>:minimum</tt>, <tt>:maximum</tt>, or <tt>:is</tt> violation. An alias of the appropriate <tt>too_long</tt>/<tt>too_short</tt>/<tt>wrong_length</tt> message.
628
628
  # * <tt>:on</tt> - Specifies when this validation is active (default is <tt>:save</tt>, other options <tt>:create</tt>, <tt>:update</tt>).
629
629
  # * <tt>:if</tt> - Specifies a method, proc or string to call to determine if the validation should
@@ -825,7 +825,7 @@ module ActiveRecord
825
825
  if scope = configuration[:scope]
826
826
  Array(scope).map do |scope_item|
827
827
  scope_value = record.send(scope_item)
828
- condition_sql << " AND " << attribute_condition("#{record.class.quoted_table_name}.#{scope_item}", scope_value)
828
+ condition_sql << " AND " << attribute_condition("#{record.class.quoted_table_name}.#{connection.quote_column_name(scope_item)}", scope_value)
829
829
  condition_params << scope_value
830
830
  end
831
831
  end
@@ -885,7 +885,7 @@ module ActiveRecord
885
885
  # class Person < ActiveRecord::Base
886
886
  # validates_inclusion_of :gender, :in => %w( m f )
887
887
  # validates_inclusion_of :age, :in => 0..99
888
- # validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension {{value}} is not included in the list"
888
+ # validates_inclusion_of :format, :in => %w( jpg gif png ), :message => "extension %{value} is not included in the list"
889
889
  # end
890
890
  #
891
891
  # Configuration options:
@@ -919,7 +919,7 @@ module ActiveRecord
919
919
  # class Person < ActiveRecord::Base
920
920
  # validates_exclusion_of :username, :in => %w( admin superuser ), :message => "You don't belong here"
921
921
  # validates_exclusion_of :age, :in => 30..60, :message => "This site is only for under 30 and over 60"
922
- # validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension {{value}} is not allowed"
922
+ # validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %{value} is not allowed"
923
923
  # end
924
924
  #
925
925
  # Configuration options:
@@ -2,7 +2,7 @@ module ActiveRecord
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 2
4
4
  MINOR = 3
5
- TINY = 8
5
+ TINY = 9
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -65,15 +65,14 @@ class AdapterTest < ActiveRecord::TestCase
65
65
  end
66
66
 
67
67
  def test_not_specifying_database_name_for_cross_database_selects
68
- assert_nothing_raised do
69
- ActiveRecord::Base.establish_connection({
70
- :adapter => 'mysql',
71
- :username => 'rails'
72
- })
73
- ActiveRecord::Base.connection.execute "SELECT activerecord_unittest.pirates.*, activerecord_unittest2.courses.* FROM activerecord_unittest.pirates, activerecord_unittest2.courses"
68
+ begin
69
+ assert_nothing_raised do
70
+ ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['arunit'].except(:database))
71
+ ActiveRecord::Base.connection.execute "SELECT activerecord_unittest.pirates.*, activerecord_unittest2.courses.* FROM activerecord_unittest.pirates, activerecord_unittest2.courses"
72
+ end
73
+ ensure
74
+ ActiveRecord::Base.establish_connection 'arunit'
74
75
  end
75
-
76
- ActiveRecord::Base.establish_connection 'arunit'
77
76
  end
78
77
  end
79
78
 
@@ -18,7 +18,7 @@ module Remembered
18
18
 
19
19
  module ClassMethods
20
20
  def remembered; @@remembered ||= []; end
21
- def random_element; @@remembered.random_element; end
21
+ def sample; @@remembered.sample; end
22
22
  end
23
23
  end
24
24
 
@@ -82,14 +82,14 @@ class EagerLoadPolyAssocsTest < ActiveRecord::TestCase
82
82
  [Circle, Square, Triangle, NonPolyOne, NonPolyTwo].map(&:create!)
83
83
  end
84
84
  1.upto(NUM_SIMPLE_OBJS) do
85
- PaintColor.create!(:non_poly_one_id => NonPolyOne.random_element.id)
86
- PaintTexture.create!(:non_poly_two_id => NonPolyTwo.random_element.id)
85
+ PaintColor.create!(:non_poly_one_id => NonPolyOne.sample.id)
86
+ PaintTexture.create!(:non_poly_two_id => NonPolyTwo.sample.id)
87
87
  end
88
88
  1.upto(NUM_SHAPE_EXPRESSIONS) do
89
- shape_type = [Circle, Square, Triangle].random_element
90
- paint_type = [PaintColor, PaintTexture].random_element
91
- ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.random_element.id,
92
- :paint_type => paint_type.to_s, :paint_id => paint_type.random_element.id)
89
+ shape_type = [Circle, Square, Triangle].sample
90
+ paint_type = [PaintColor, PaintTexture].sample
91
+ ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.sample.id,
92
+ :paint_type => paint_type.to_s, :paint_id => paint_type.sample.id)
93
93
  end
94
94
  end
95
95
 
@@ -0,0 +1,19 @@
1
+ require 'cases/helper'
2
+ require 'models/tee'
3
+ require 'models/tie'
4
+ require 'models/polymorphic_design'
5
+ require 'models/polymorphic_price'
6
+
7
+ class EagerLoadNestedPolymorphicIncludeTest < ActiveRecord::TestCase
8
+ fixtures :tees, :ties, :polymorphic_designs, :polymorphic_prices
9
+
10
+ def test_eager_load_polymorphic_has_one_nested_under_polymorphic_belongs_to
11
+ designs = PolymorphicDesign.scoped(:include => {:designable => :polymorphic_price})
12
+
13
+ associated_price_ids = designs.map{|design| design.designable.polymorphic_price.id}
14
+ expected_price_ids = [1, 2, 3, 4]
15
+
16
+ assert expected_price_ids.all?{|expected_id| associated_price_ids.include?(expected_id)},
17
+ "Expected associated prices to be #{expected_price_ids.inspect} but they were #{associated_price_ids.sort.inspect}"
18
+ end
19
+ end
@@ -357,6 +357,13 @@ class EagerAssociationTest < ActiveRecord::TestCase
357
357
  assert_equal comments(:more_greetings), Author.find(authors(:david).id, :include => :comments_with_order_and_conditions).comments_with_order_and_conditions.first
358
358
  end
359
359
 
360
+ def test_eager_with_has_many_through_with_conditions_join_model_with_include
361
+ post_tags = Post.find(posts(:welcome).id).misc_tags
362
+ eager_post_tags = Post.find(1, :include => :misc_tags).misc_tags
363
+ assert_equal post_tags, eager_post_tags
364
+ end
365
+
366
+
360
367
  def test_eager_with_has_many_through_join_model_with_include
361
368
  author_comments = Author.find(authors(:david).id, :include => :comments_with_include).comments_with_include.to_a
362
369
  assert_no_queries do
@@ -21,6 +21,68 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
21
21
  Client.destroyed_client_ids.clear
22
22
  end
23
23
 
24
+ def test_create_by
25
+ person = Person.create! :first_name => 'tenderlove'
26
+ post = Post.find :first
27
+
28
+ assert_equal [], person.readers
29
+ assert_nil person.readers.find_by_post_id post.id
30
+
31
+ reader = person.readers.create_by_post_id post.id
32
+
33
+ assert_equal 1, person.readers.count
34
+ assert_equal 1, person.readers.length
35
+ assert_equal post, person.readers.first.post
36
+ assert_equal person, person.readers.first.person
37
+ end
38
+
39
+ def test_create_by_multi
40
+ person = Person.create! :first_name => 'tenderlove'
41
+ post = Post.find :first
42
+
43
+ assert_equal [], person.readers
44
+
45
+ reader = person.readers.create_by_post_id_and_skimmer post.id, false
46
+
47
+ assert_equal 1, person.readers.count
48
+ assert_equal 1, person.readers.length
49
+ assert_equal post, person.readers.first.post
50
+ assert_equal person, person.readers.first.person
51
+ end
52
+
53
+ def test_find_or_create_by
54
+ person = Person.create! :first_name => 'tenderlove'
55
+ post = Post.find :first
56
+
57
+ assert_equal [], person.readers
58
+ assert_nil person.readers.find_by_post_id post.id
59
+
60
+ reader = person.readers.find_or_create_by_post_id post.id
61
+
62
+ assert_equal 1, person.readers.count
63
+ assert_equal 1, person.readers.length
64
+ assert_equal post, person.readers.first.post
65
+ assert_equal person, person.readers.first.person
66
+ end
67
+
68
+ def test_find_or_create
69
+ person = Person.create! :first_name => 'tenderlove'
70
+ post = Post.find :first
71
+
72
+ assert_equal [], person.readers
73
+ assert_nil person.readers.find(:first, :conditions => {
74
+ :post_id => post.id
75
+ })
76
+
77
+ reader = person.readers.find_or_create :post_id => post.id
78
+
79
+ assert_equal 1, person.readers.count
80
+ assert_equal 1, person.readers.length
81
+ assert_equal post, person.readers.first.post
82
+ assert_equal person, person.readers.first.person
83
+ end
84
+
85
+
24
86
  def force_signal37_to_load_all_clients_of_firm
25
87
  companies(:first_firm).clients_of_firm.each {|f| }
26
88
  end
@@ -486,7 +548,7 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
486
548
  assert the_client.new_record?
487
549
  end
488
550
 
489
- def test_find_or_create
551
+ def test_find_or_create_updates_size
490
552
  number_of_clients = companies(:first_firm).clients.size
491
553
  the_client = companies(:first_firm).clients.find_or_create_by_name("Yet another client")
492
554
  assert_equal number_of_clients + 1, companies(:first_firm, :reload).clients.size
@@ -772,8 +834,11 @@ class HasManyAssociationsTest < ActiveRecord::TestCase
772
834
 
773
835
  def test_destroy_all
774
836
  force_signal37_to_load_all_clients_of_firm
775
- assert !companies(:first_firm).clients_of_firm.empty?, "37signals has clients after load"
776
- companies(:first_firm).clients_of_firm.destroy_all
837
+ clients = companies(:first_firm).clients_of_firm.to_a
838
+ assert !clients.empty?, "37signals has clients after load"
839
+ destroyed = companies(:first_firm).clients_of_firm.destroy_all
840
+ assert_equal clients.sort_by(&:id), destroyed.sort_by(&:id)
841
+ assert destroyed.all? { |client| client.frozen? }, "destroyed clients should be frozen"
777
842
  assert companies(:first_firm).clients_of_firm.empty?, "37signals has no clients after destroy all"
778
843
  assert companies(:first_firm).clients_of_firm(true).empty?, "37signals has no clients after destroy all and refresh"
779
844
  end
@@ -18,6 +18,8 @@ require 'models/person'
18
18
  require 'models/reader'
19
19
  require 'models/parrot'
20
20
  require 'models/pirate'
21
+ require 'models/ship'
22
+ require 'models/ship_part'
21
23
  require 'models/treasure'
22
24
  require 'models/price_estimate'
23
25
  require 'models/club'
@@ -29,6 +31,23 @@ class AssociationsTest < ActiveRecord::TestCase
29
31
  fixtures :accounts, :companies, :developers, :projects, :developers_projects,
30
32
  :computers, :people, :readers
31
33
 
34
+ def test_loading_the_association_target_should_keep_child_records_marked_for_destruction
35
+ ship = Ship.create!(:name => "The good ship Dollypop")
36
+ part = ship.parts.create!(:name => "Mast")
37
+ part.mark_for_destruction
38
+ ship.parts.send(:load_target)
39
+ assert ship.parts[0].marked_for_destruction?
40
+ end
41
+
42
+ def test_loading_the_association_target_should_load_most_recent_attributes_for_child_records_marked_for_destruction
43
+ ship = Ship.create!(:name => "The good ship Dollypop")
44
+ part = ship.parts.create!(:name => "Mast")
45
+ part.mark_for_destruction
46
+ ShipPart.find(part.id).update_attribute(:name, 'Deck')
47
+ ship.parts.send(:load_target)
48
+ assert_equal 'Deck', ship.parts[0].name
49
+ end
50
+
32
51
  def test_include_with_order_works
33
52
  assert_nothing_raised {Account.find(:first, :order => 'id', :include => :firm)}
34
53
  assert_nothing_raised {Account.find(:first, :order => :id, :include => :firm)}
@@ -74,6 +93,16 @@ class AssociationsTest < ActiveRecord::TestCase
74
93
  assert_queries(1) { assert_not_nil firm.clients(true).each {} }
75
94
  end
76
95
  end
96
+
97
+ def test_using_limitable_reflections_helper
98
+ using_limitable_reflections = lambda { |reflections| ActiveRecord::Base.send :using_limitable_reflections?, reflections }
99
+ belongs_to_reflections = [Tagging.reflect_on_association(:tag), Tagging.reflect_on_association(:super_tag)]
100
+ has_many_reflections = [Tag.reflect_on_association(:taggings), Developer.reflect_on_association(:projects)]
101
+ mixed_reflections = (belongs_to_reflections + has_many_reflections).uniq
102
+ assert using_limitable_reflections.call(belongs_to_reflections), "Belong to associations are limitable"
103
+ assert !using_limitable_reflections.call(has_many_reflections), "All has many style associations are not limitable"
104
+ assert !using_limitable_reflections.call(mixed_reflections), "No collection associations (has many style) should pass"
105
+ end
77
106
 
78
107
  def test_storing_in_pstore
79
108
  require "tmpdir"
@@ -1,6 +1,5 @@
1
1
  require "cases/helper"
2
2
  require 'models/post'
3
- require 'models/author'
4
3
  require 'models/event_author'
5
4
  require 'models/topic'
6
5
  require 'models/reply'
@@ -588,17 +587,25 @@ class BasicsTest < ActiveRecord::TestCase
588
587
  end
589
588
 
590
589
  def test_destroy_all
591
- original_count = Topic.count
592
- topics_by_mary = Topic.count(:conditions => mary = "author_name = 'Mary'")
593
-
594
- Topic.destroy_all mary
595
- assert_equal original_count - topics_by_mary, Topic.count
590
+ conditions = "author_name = 'Mary'"
591
+ topics_by_mary = Topic.all(:conditions => conditions, :order => 'id')
592
+ assert ! topics_by_mary.empty?
593
+
594
+ assert_difference('Topic.count', -topics_by_mary.size) do
595
+ destroyed = Topic.destroy_all(conditions).sort_by(&:id)
596
+ assert_equal topics_by_mary, destroyed
597
+ assert destroyed.all? { |topic| topic.frozen? }
598
+ end
596
599
  end
597
600
 
598
601
  def test_destroy_many
599
- assert_equal 3, Client.count
600
- Client.destroy([2, 3])
601
- assert_equal 1, Client.count
602
+ clients = Client.find([2, 3], :order => 'id')
603
+
604
+ assert_difference('Client.count', -2) do
605
+ destroyed = Client.destroy([2, 3]).sort_by(&:id)
606
+ assert_equal clients, destroyed
607
+ assert destroyed.all? { |client| client.frozen? }
608
+ end
602
609
  end
603
610
 
604
611
  def test_delete_many
@@ -612,55 +619,6 @@ class BasicsTest < ActiveRecord::TestCase
612
619
  assert Topic.find(2).approved?
613
620
  end
614
621
 
615
- def test_increment_counter
616
- Topic.increment_counter("replies_count", 1)
617
- assert_equal 2, Topic.find(1).replies_count
618
-
619
- Topic.increment_counter("replies_count", 1)
620
- assert_equal 3, Topic.find(1).replies_count
621
- end
622
-
623
- def test_decrement_counter
624
- Topic.decrement_counter("replies_count", 2)
625
- assert_equal -1, Topic.find(2).replies_count
626
-
627
- Topic.decrement_counter("replies_count", 2)
628
- assert_equal -2, Topic.find(2).replies_count
629
- end
630
-
631
- def test_reset_counters
632
- assert_equal 1, Topic.find(1).replies_count
633
-
634
- Topic.increment_counter("replies_count", 1)
635
- assert_equal 2, Topic.find(1).replies_count
636
-
637
- Topic.reset_counters(1, :replies)
638
- assert_equal 1, Topic.find(1).replies_count
639
- end
640
-
641
- def test_update_counter
642
- category = categories(:general)
643
- assert_nil category.categorizations_count
644
- assert_equal 2, category.categorizations.count
645
-
646
- Category.update_counters(category.id, "categorizations_count" => category.categorizations.count)
647
- category.reload
648
- assert_not_nil category.categorizations_count
649
- assert_equal 2, category.categorizations_count
650
-
651
- Category.update_counters(category.id, "categorizations_count" => category.categorizations.count)
652
- category.reload
653
- assert_not_nil category.categorizations_count
654
- assert_equal 4, category.categorizations_count
655
-
656
- category_2 = categories(:technology)
657
- count_1, count_2 = (category.categorizations_count || 0), (category_2.categorizations_count || 0)
658
- Category.update_counters([category.id, category_2.id], "categorizations_count" => 2)
659
- category.reload; category_2.reload
660
- assert_equal count_1 + 2, category.categorizations_count
661
- assert_equal count_2 + 2, category_2.categorizations_count
662
- end
663
-
664
622
  def test_update_all
665
623
  assert_equal Topic.count, Topic.update_all("content = 'bulk updated!'")
666
624
  assert_equal "bulk updated!", Topic.find(1).content
@@ -749,22 +707,24 @@ class BasicsTest < ActiveRecord::TestCase
749
707
  end
750
708
 
751
709
  def test_class_name
752
- assert_equal "Firm", ActiveRecord::Base.class_name("firms")
753
- assert_equal "Category", ActiveRecord::Base.class_name("categories")
754
- assert_equal "AccountHolder", ActiveRecord::Base.class_name("account_holder")
755
-
756
- ActiveRecord::Base.pluralize_table_names = false
757
- assert_equal "Firms", ActiveRecord::Base.class_name( "firms" )
758
- ActiveRecord::Base.pluralize_table_names = true
759
-
760
- ActiveRecord::Base.table_name_prefix = "test_"
761
- assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms" )
762
- ActiveRecord::Base.table_name_suffix = "_tests"
763
- assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms_tests" )
764
- ActiveRecord::Base.table_name_prefix = ""
765
- assert_equal "Firm", ActiveRecord::Base.class_name( "firms_tests" )
766
- ActiveRecord::Base.table_name_suffix = ""
767
- assert_equal "Firm", ActiveRecord::Base.class_name( "firms" )
710
+ ActiveSupport::Deprecation.silence do
711
+ assert_equal "Firm", ActiveRecord::Base.class_name("firms")
712
+ assert_equal "Category", ActiveRecord::Base.class_name("categories")
713
+ assert_equal "AccountHolder", ActiveRecord::Base.class_name("account_holder")
714
+
715
+ ActiveRecord::Base.pluralize_table_names = false
716
+ assert_equal "Firms", ActiveRecord::Base.class_name( "firms" )
717
+ ActiveRecord::Base.pluralize_table_names = true
718
+
719
+ ActiveRecord::Base.table_name_prefix = "test_"
720
+ assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms" )
721
+ ActiveRecord::Base.table_name_suffix = "_tests"
722
+ assert_equal "Firm", ActiveRecord::Base.class_name( "test_firms_tests" )
723
+ ActiveRecord::Base.table_name_prefix = ""
724
+ assert_equal "Firm", ActiveRecord::Base.class_name( "firms_tests" )
725
+ ActiveRecord::Base.table_name_suffix = ""
726
+ assert_equal "Firm", ActiveRecord::Base.class_name( "firms" )
727
+ end
768
728
  end
769
729
 
770
730
  def test_null_fields
@@ -2090,7 +2050,7 @@ class BasicsTest < ActiveRecord::TestCase
2090
2050
 
2091
2051
  def test_inspect_instance
2092
2052
  topic = topics(:first)
2093
- assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil>), topic.inspect
2053
+ assert_equal %(#<Topic id: 1, title: "The First Topic", author_name: "David", author_email_address: "david@loudthinking.com", written_on: "#{topic.written_on.to_s(:db)}", bonus_time: "#{topic.bonus_time.to_s(:db)}", last_read: "#{topic.last_read.to_s(:db)}", content: "Have a nice day", approved: false, replies_count: 1, parent_id: nil, parent_title: nil, type: nil, group: nil>), topic.inspect
2094
2054
  end
2095
2055
 
2096
2056
  def test_inspect_new_instance