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.
- data/CHANGELOG +1 -4
- data/Rakefile +1 -1
- data/examples/performance.rb +2 -0
- data/lib/active_record/association_preload.rb +12 -2
- data/lib/active_record/associations.rb +1 -1
- data/lib/active_record/associations/association_collection.rb +33 -4
- data/lib/active_record/attribute_methods.rb +0 -4
- data/lib/active_record/autosave_association.rb +2 -2
- data/lib/active_record/base.rb +28 -16
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +1 -1
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +1 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +6 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +2 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +2 -1
- data/lib/active_record/dirty.rb +1 -1
- data/lib/active_record/locale/en.yml +11 -11
- data/lib/active_record/locking/optimistic.rb +1 -0
- data/lib/active_record/migration.rb +1 -1
- data/lib/active_record/named_scope.rb +14 -9
- data/lib/active_record/nested_attributes.rb +11 -8
- data/lib/active_record/serialization.rb +1 -1
- data/lib/active_record/session_store.rb +9 -1
- data/lib/active_record/validations.rb +12 -12
- data/lib/active_record/version.rb +1 -1
- data/test/cases/adapter_test.rb +7 -8
- data/test/cases/associations/eager_load_nested_include_test.rb +7 -7
- data/test/cases/associations/eager_load_nested_polymorphic_include.rb +19 -0
- data/test/cases/associations/eager_test.rb +7 -0
- data/test/cases/associations/has_many_associations_test.rb +68 -3
- data/test/cases/associations_test.rb +29 -0
- data/test/cases/base_test.rb +35 -75
- data/test/cases/connection_test_mysql.rb +1 -0
- data/test/cases/counter_cache_test.rb +84 -0
- data/test/cases/locking_test.rb +2 -1
- data/test/cases/migration_test.rb +4 -0
- data/test/cases/named_scope_test.rb +6 -1
- data/test/cases/nested_attributes_test.rb +49 -14
- data/test/cases/reflection_test.rb +5 -5
- data/test/cases/sp_test_mysql.rb +16 -0
- data/test/cases/transactions_test.rb +22 -1
- data/test/cases/validations_i18n_test.rb +12 -12
- data/test/cases/validations_test.rb +42 -30
- data/test/fixtures/fixture_database.sqlite3 +0 -0
- data/test/fixtures/fixture_database_2.sqlite3 +0 -0
- data/test/fixtures/polymorphic_designs.yml +19 -0
- data/test/fixtures/polymorphic_prices.yml +19 -0
- data/test/fixtures/tees.yml +4 -0
- data/test/fixtures/ties.yml +4 -0
- data/test/models/author.rb +2 -0
- data/test/models/event_author.rb +3 -0
- data/test/models/pirate.rb +2 -2
- data/test/models/polymorphic_design.rb +3 -0
- data/test/models/polymorphic_price.rb +3 -0
- data/test/models/post.rb +2 -0
- data/test/models/tee.rb +4 -0
- data/test/models/tie.rb +4 -0
- data/test/schema/mysql_specific_schema.rb +7 -0
- data/test/schema/schema.rb +16 -0
- metadata +24 -13
- data/examples/performance.sql +0 -85
- data/test/cases/encoding_test.rb +0 -6
- data/test/fixtures/fixture_database.sqlite +0 -0
- 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
|
-
|
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
|
-
|
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
|
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
|
-
|
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 =
|
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>"{
|
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
|
-
'{
|
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 {
|
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 {
|
612
|
-
# validates_length_of :smurf_leader, :is => 4, :message => "papa is spelled with {
|
613
|
-
# validates_length_of :essay, :minimum => 100, :too_short => "Your essay must be at least {
|
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 {
|
625
|
-
# * <tt>:too_short</tt> - The error message if the attribute goes under the minimum (default is: "is too short (min is {
|
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 {
|
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 {
|
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 {
|
922
|
+
# validates_exclusion_of :format, :in => %w( mov avi ), :message => "extension %{value} is not allowed"
|
923
923
|
# end
|
924
924
|
#
|
925
925
|
# Configuration options:
|
data/test/cases/adapter_test.rb
CHANGED
@@ -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
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
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
|
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.
|
86
|
-
PaintTexture.create!(:non_poly_two_id => NonPolyTwo.
|
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].
|
90
|
-
paint_type = [PaintColor, PaintTexture].
|
91
|
-
ShapeExpression.create!(:shape_type => shape_type.to_s, :shape_id => shape_type.
|
92
|
-
:paint_type => paint_type.to_s, :paint_id => paint_type.
|
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
|
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
|
-
|
776
|
-
|
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"
|
data/test/cases/base_test.rb
CHANGED
@@ -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
|
-
|
592
|
-
topics_by_mary = Topic.
|
593
|
-
|
594
|
-
|
595
|
-
|
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
|
-
|
600
|
-
|
601
|
-
|
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
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
|
765
|
-
|
766
|
-
|
767
|
-
|
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
|