activerecord 2.0.1 → 2.0.2
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 +48 -32
- data/README +0 -14
- data/Rakefile +2 -1
- data/lib/active_record/associations/association_proxy.rb +15 -14
- data/lib/active_record/associations/has_many_through_association.rb +2 -1
- data/lib/active_record/base.rb +184 -111
- data/lib/active_record/calculations.rb +2 -4
- data/lib/active_record/fixtures.rb +19 -3
- data/lib/active_record/locking/optimistic.rb +1 -1
- data/lib/active_record/validations.rb +37 -4
- data/lib/active_record/version.rb +1 -1
- data/test/aaa_create_tables_test.rb +2 -2
- data/test/associations/join_model_test.rb +6 -0
- data/test/associations_test.rb +8 -1
- data/test/finder_test.rb +9 -1
- data/test/fixtures/author.rb +2 -0
- data/test/fixtures_test.rb +16 -0
- data/test/locking_test.rb +9 -0
- data/test/validations_test.rb +8 -0
- metadata +49 -43
- data/test/associations/ar_joins_test.rb +0 -0
@@ -15,12 +15,10 @@ module ActiveRecord
|
|
15
15
|
# The third approach, count using options, accepts an option hash as the only parameter. The options are:
|
16
16
|
#
|
17
17
|
# * <tt>:conditions</tt>: An SQL fragment like "administrator = 1" or [ "user_name = ?", username ]. See conditions in the intro.
|
18
|
-
# * <tt>:joins</tt>: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id"
|
19
|
-
#
|
18
|
+
# * <tt>:joins</tt>: Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed)
|
19
|
+
# or named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s).
|
20
20
|
# If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns.
|
21
21
|
# Pass :readonly => false to override.
|
22
|
-
# See adding joins for associations under Associations.
|
23
|
-
#
|
24
22
|
# * <tt>:include</tt>: Named associations that should be loaded alongside using LEFT OUTER JOINs. The symbols named refer
|
25
23
|
# to already defined associations. When using named associations, count returns the number of DISTINCT items for the model you're counting.
|
26
24
|
# See eager loading under Associations.
|
@@ -9,7 +9,12 @@ module YAML #:nodoc:
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
|
12
|
+
if defined? ActiveRecord
|
13
|
+
class FixtureClassNotFound < ActiveRecord::ActiveRecordError #:nodoc:
|
14
|
+
end
|
15
|
+
else
|
16
|
+
class FixtureClassNotFound < StandardError #:nodoc:
|
17
|
+
end
|
13
18
|
end
|
14
19
|
|
15
20
|
# Fixtures are a way of organizing data that you want to test against; in short, sample data. They come in 3 flavors:
|
@@ -911,6 +916,8 @@ module Test #:nodoc:
|
|
911
916
|
end
|
912
917
|
|
913
918
|
def setup_with_fixtures
|
919
|
+
return if @fixtures_setup
|
920
|
+
@fixtures_setup = true
|
914
921
|
return unless defined?(ActiveRecord::Base) && !ActiveRecord::Base.configurations.blank?
|
915
922
|
|
916
923
|
if pre_loaded_fixtures && !use_transactional_fixtures
|
@@ -942,6 +949,8 @@ module Test #:nodoc:
|
|
942
949
|
alias_method :setup, :setup_with_fixtures
|
943
950
|
|
944
951
|
def teardown_with_fixtures
|
952
|
+
return if @fixtures_teardown
|
953
|
+
@fixtures_teardown = true
|
945
954
|
return unless defined?(ActiveRecord::Base) && !ActiveRecord::Base.configurations.blank?
|
946
955
|
|
947
956
|
unless use_transactional_fixtures?
|
@@ -958,24 +967,31 @@ module Test #:nodoc:
|
|
958
967
|
alias_method :teardown, :teardown_with_fixtures
|
959
968
|
|
960
969
|
def self.method_added(method)
|
970
|
+
return if @__disable_method_added__
|
971
|
+
@__disable_method_added__ = true
|
972
|
+
|
961
973
|
case method.to_s
|
962
974
|
when 'setup'
|
963
975
|
unless method_defined?(:setup_without_fixtures)
|
964
976
|
alias_method :setup_without_fixtures, :setup
|
965
|
-
define_method(:
|
977
|
+
define_method(:full_setup) do
|
966
978
|
setup_with_fixtures
|
967
979
|
setup_without_fixtures
|
968
980
|
end
|
969
981
|
end
|
982
|
+
alias_method :setup, :full_setup
|
970
983
|
when 'teardown'
|
971
984
|
unless method_defined?(:teardown_without_fixtures)
|
972
985
|
alias_method :teardown_without_fixtures, :teardown
|
973
|
-
define_method(:
|
986
|
+
define_method(:full_teardown) do
|
974
987
|
teardown_without_fixtures
|
975
988
|
teardown_with_fixtures
|
976
989
|
end
|
977
990
|
end
|
991
|
+
alias_method :teardown, :full_teardown
|
978
992
|
end
|
993
|
+
|
994
|
+
@__disable_method_added__ = false
|
979
995
|
end
|
980
996
|
|
981
997
|
private
|
@@ -297,7 +297,33 @@ module ActiveRecord
|
|
297
297
|
:equal_to => '==', :less_than => '<', :less_than_or_equal_to => '<=',
|
298
298
|
:odd => 'odd?', :even => 'even?' }.freeze
|
299
299
|
|
300
|
-
|
300
|
+
# Adds a validation method or block to the class. This is useful when
|
301
|
+
# overriding the #validate instance method becomes too unwieldly and
|
302
|
+
# you're looking for more descriptive declaration of your validations.
|
303
|
+
#
|
304
|
+
# This can be done with a symbol pointing to a method:
|
305
|
+
#
|
306
|
+
# class Comment < ActiveRecord::Base
|
307
|
+
# validate :must_be_friends
|
308
|
+
#
|
309
|
+
# def must_be_friends
|
310
|
+
# errors.add_to_base("Must be friends to leave a comment") unless commenter.friend_of?(commentee)
|
311
|
+
# end
|
312
|
+
# end
|
313
|
+
#
|
314
|
+
# Or with a block which is passed the current record to be validated:
|
315
|
+
#
|
316
|
+
# class Comment < ActiveRecord::Base
|
317
|
+
# validate do |comment|
|
318
|
+
# comment.must_be_friends
|
319
|
+
# end
|
320
|
+
#
|
321
|
+
# def must_be_friends
|
322
|
+
# errors.add_to_base("Must be friends to leave a comment") unless commenter.friend_of?(commentee)
|
323
|
+
# end
|
324
|
+
# end
|
325
|
+
#
|
326
|
+
# This usage applies to #validate_on_create and #validate_on_update as well.
|
301
327
|
def validate(*methods, &block)
|
302
328
|
methods << block if block_given?
|
303
329
|
write_inheritable_set(:validate, methods)
|
@@ -403,7 +429,7 @@ module ActiveRecord
|
|
403
429
|
configuration = { :message => ActiveRecord::Errors.default_error_messages[:confirmation], :on => :save }
|
404
430
|
configuration.update(attr_names.extract_options!)
|
405
431
|
|
406
|
-
attr_accessor
|
432
|
+
attr_accessor(*(attr_names.map { |n| "#{n}_confirmation" }))
|
407
433
|
|
408
434
|
validates_each(attr_names, configuration) do |record, attr_name, value|
|
409
435
|
record.errors.add(attr_name, configuration[:message]) unless record.send("#{attr_name}_confirmation").nil? or value == record.send("#{attr_name}_confirmation")
|
@@ -425,7 +451,8 @@ module ActiveRecord
|
|
425
451
|
# * <tt>on</tt> - Specifies when this validation is active (default is :save, other options :create, :update)
|
426
452
|
# * <tt>allow_nil</tt> - Skip validation if attribute is nil. (default is true)
|
427
453
|
# * <tt>accept</tt> - Specifies value that is considered accepted. The default value is a string "1", which
|
428
|
-
# makes it easy to relate to an HTML checkbox.
|
454
|
+
# makes it easy to relate to an HTML checkbox. This should be set to 'true' if you are validating a database
|
455
|
+
# column, since the attribute is typecast from "1" to <tt>true</tt> before validation.
|
429
456
|
# * <tt>if</tt> - Specifies a method, proc or string to call to determine if the validation should
|
430
457
|
# occur (e.g. :if => :allow_validation, or :if => Proc.new { |user| user.signup_step > 2 }). The
|
431
458
|
# method, proc or string should return or evaluate to a true or false value.
|
@@ -436,7 +463,13 @@ module ActiveRecord
|
|
436
463
|
configuration = { :message => ActiveRecord::Errors.default_error_messages[:accepted], :on => :save, :allow_nil => true, :accept => "1" }
|
437
464
|
configuration.update(attr_names.extract_options!)
|
438
465
|
|
439
|
-
|
466
|
+
db_cols = begin
|
467
|
+
column_names
|
468
|
+
rescue ActiveRecord::StatementInvalid
|
469
|
+
[]
|
470
|
+
end
|
471
|
+
names = attr_names.reject { |name| db_cols.include?(name.to_s) }
|
472
|
+
attr_accessor(*names)
|
440
473
|
|
441
474
|
validates_each(attr_names,configuration) do |record, attr_name, value|
|
442
475
|
record.errors.add(attr_name, configuration[:message]) unless value == configuration[:accept]
|
@@ -33,12 +33,12 @@ class AAACreateTablesTest < Test::Unit::TestCase
|
|
33
33
|
private
|
34
34
|
def use_migrations?
|
35
35
|
unittest_sql_filename = ActiveRecord::Base.connection.adapter_name.downcase + ".sql"
|
36
|
-
not File.
|
36
|
+
not File.exist? "#{@base_path}/#{unittest_sql_filename}"
|
37
37
|
end
|
38
38
|
|
39
39
|
def use_migrations_for_courses?
|
40
40
|
unittest2_sql_filename = ActiveRecord::Base.connection.adapter_name.downcase + "2.sql"
|
41
|
-
not File.
|
41
|
+
not File.exist? "#{@base_path}/#{unittest2_sql_filename}"
|
42
42
|
end
|
43
43
|
|
44
44
|
def recreate(base, suffix = nil)
|
@@ -539,6 +539,12 @@ class AssociationsJoinModelTest < Test::Unit::TestCase
|
|
539
539
|
def test_has_many_through_has_many_with_sti
|
540
540
|
assert_equal [comments(:does_it_hurt)], authors(:david).special_post_comments
|
541
541
|
end
|
542
|
+
|
543
|
+
def test_uniq_has_many_through_should_retain_order
|
544
|
+
comment_ids = authors(:david).comments.map(&:id)
|
545
|
+
assert_equal comment_ids.sort, authors(:david).ordered_uniq_comments.map(&:id)
|
546
|
+
assert_equal comment_ids.sort.reverse, authors(:david).ordered_uniq_comments_desc.map(&:id)
|
547
|
+
end
|
542
548
|
|
543
549
|
private
|
544
550
|
# create dynamic Post models to allow different dependency options
|
data/test/associations_test.rb
CHANGED
@@ -55,7 +55,7 @@ class AssociationsTest < Test::Unit::TestCase
|
|
55
55
|
def test_storing_in_pstore
|
56
56
|
require "tmpdir"
|
57
57
|
store_filename = File.join(Dir.tmpdir, "ar-pstore-association-test")
|
58
|
-
File.delete(store_filename) if File.
|
58
|
+
File.delete(store_filename) if File.exist?(store_filename)
|
59
59
|
require "pstore"
|
60
60
|
apple = Firm.create("name" => "Apple")
|
61
61
|
natural = Client.new("name" => "Natural Company")
|
@@ -133,6 +133,13 @@ class AssociationProxyTest < Test::Unit::TestCase
|
|
133
133
|
assert_nil p.author.reset
|
134
134
|
end
|
135
135
|
|
136
|
+
def test_reload_returns_assocition
|
137
|
+
david = developers(:david)
|
138
|
+
assert_nothing_raised do
|
139
|
+
assert_equal david.projects, david.projects.reload.reload
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
136
143
|
def setup_dangling_association
|
137
144
|
josh = Author.create(:name => "Josh")
|
138
145
|
p = Post.create(:title => "New on Edge", :body => "More cool stuff!", :author => josh)
|
data/test/finder_test.rb
CHANGED
@@ -28,7 +28,15 @@ class FinderTest < Test::Unit::TestCase
|
|
28
28
|
assert Topic.exists?(:author_name => "Mary", :approved => true)
|
29
29
|
assert Topic.exists?(["parent_id = ?", 1])
|
30
30
|
assert !Topic.exists?(45)
|
31
|
-
|
31
|
+
|
32
|
+
begin
|
33
|
+
assert !Topic.exists?("foo")
|
34
|
+
rescue ActiveRecord::StatementInvalid
|
35
|
+
# PostgreSQL complains about string comparison with integer field
|
36
|
+
rescue Exception
|
37
|
+
flunk
|
38
|
+
end
|
39
|
+
|
32
40
|
assert_raise(NoMethodError) { Topic.exists?([1,2]) }
|
33
41
|
end
|
34
42
|
|
data/test/fixtures/author.rb
CHANGED
@@ -18,6 +18,8 @@ class Author < ActiveRecord::Base
|
|
18
18
|
has_many :comments_desc, :through => :posts, :source => :comments, :order => 'comments.id DESC'
|
19
19
|
has_many :limited_comments, :through => :posts, :source => :comments, :limit => 1
|
20
20
|
has_many :funky_comments, :through => :posts, :source => :comments
|
21
|
+
has_many :ordered_uniq_comments, :through => :posts, :source => :comments, :uniq => true, :order => 'comments.id'
|
22
|
+
has_many :ordered_uniq_comments_desc, :through => :posts, :source => :comments, :uniq => true, :order => 'comments.id DESC'
|
21
23
|
|
22
24
|
has_many :special_posts
|
23
25
|
has_many :special_post_comments, :through => :special_posts, :source => :comments
|
data/test/fixtures_test.rb
CHANGED
@@ -324,6 +324,22 @@ class MultipleFixturesTest < Test::Unit::TestCase
|
|
324
324
|
end
|
325
325
|
end
|
326
326
|
|
327
|
+
# This is to reproduce a bug where if a TestCase is loaded
|
328
|
+
# twice by Ruby, it loses its fixture setup hook.
|
329
|
+
class_def = <<-CODE
|
330
|
+
class DoubleLoadedTestCase < Test::Unit::TestCase
|
331
|
+
fixtures :topics
|
332
|
+
|
333
|
+
def setup
|
334
|
+
end
|
335
|
+
|
336
|
+
def test_should_properly_setup_fixtures
|
337
|
+
assert_nothing_raised { topics(:first) }
|
338
|
+
end
|
339
|
+
end
|
340
|
+
CODE
|
341
|
+
2.times { eval(class_def) }
|
342
|
+
|
327
343
|
class OverlappingFixturesTest < Test::Unit::TestCase
|
328
344
|
fixtures :topics, :developers
|
329
345
|
fixtures :developers, :accounts
|
data/test/locking_test.rb
CHANGED
@@ -64,6 +64,15 @@ class OptimisticLockingTest < Test::Unit::TestCase
|
|
64
64
|
|
65
65
|
assert_raises(ActiveRecord::StaleObjectError) { p2.save! }
|
66
66
|
end
|
67
|
+
|
68
|
+
def test_lock_new_with_nil
|
69
|
+
p1 = Person.new(:first_name => 'anika')
|
70
|
+
p1.save!
|
71
|
+
p1.lock_version = nil # simulate bad fixture or column with no default
|
72
|
+
p1.save!
|
73
|
+
assert_equal 1, p1.lock_version
|
74
|
+
end
|
75
|
+
|
67
76
|
|
68
77
|
def test_lock_column_name_existing
|
69
78
|
t1 = LegacyThing.find(1)
|
data/test/validations_test.rb
CHANGED
@@ -301,6 +301,14 @@ class ValidationsTest < Test::Unit::TestCase
|
|
301
301
|
assert_equal "Dan Brown", reply["author_name"]
|
302
302
|
end
|
303
303
|
|
304
|
+
def test_validates_acceptance_of_with_non_existant_table
|
305
|
+
Object.const_set :IncorporealModel, Class.new(ActiveRecord::Base)
|
306
|
+
|
307
|
+
assert_nothing_raised ActiveRecord::StatementInvalid do
|
308
|
+
IncorporealModel.validates_acceptance_of(:incorporeal_column)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
304
312
|
def test_validate_presences
|
305
313
|
Topic.validates_presence_of(:title, :content)
|
306
314
|
|
metadata
CHANGED
@@ -1,33 +1,34 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.4
|
3
|
-
specification_version: 1
|
4
2
|
name: activerecord
|
5
3
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 2.0.
|
7
|
-
date: 2007-12-07 00:00:00 -06:00
|
8
|
-
summary: Implements the ActiveRecord pattern for ORM.
|
9
|
-
require_paths:
|
10
|
-
- lib
|
11
|
-
email: david@loudthinking.com
|
12
|
-
homepage: http://www.rubyonrails.org
|
13
|
-
rubyforge_project: activerecord
|
14
|
-
description: Implements the ActiveRecord pattern (Fowler, PoEAA) for ORM. It ties database tables and classes together for business objects, like Customer or Subscription, that can find, save, and destroy themselves without resorting to manual SQL.
|
15
|
-
autorequire: active_record
|
16
|
-
default_executable:
|
17
|
-
bindir: bin
|
18
|
-
has_rdoc: true
|
19
|
-
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">"
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 0.0.0
|
24
|
-
version:
|
4
|
+
version: 2.0.2
|
25
5
|
platform: ruby
|
26
|
-
signing_key:
|
27
|
-
cert_chain:
|
28
|
-
post_install_message:
|
29
6
|
authors:
|
30
7
|
- David Heinemeier Hansson
|
8
|
+
autorequire: active_record
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2007-12-20 00:00:00 -06:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: activesupport
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - "="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 2.0.2
|
23
|
+
version:
|
24
|
+
description: Implements the ActiveRecord pattern (Fowler, PoEAA) for ORM. It ties database tables and classes together for business objects, like Customer or Subscription, that can find, save, and destroy themselves without resorting to manual SQL.
|
25
|
+
email: david@loudthinking.com
|
26
|
+
executables: []
|
27
|
+
|
28
|
+
extensions: []
|
29
|
+
|
30
|
+
extra_rdoc_files:
|
31
|
+
- README
|
31
32
|
files:
|
32
33
|
- Rakefile
|
33
34
|
- install.rb
|
@@ -96,7 +97,6 @@ files:
|
|
96
97
|
- test/ar_schema_test.rb
|
97
98
|
- test/association_inheritance_reload.rb
|
98
99
|
- test/associations
|
99
|
-
- test/associations/ar_joins_test.rb
|
100
100
|
- test/associations/callbacks_test.rb
|
101
101
|
- test/associations/cascaded_eager_loading_test.rb
|
102
102
|
- test/associations/eager_singularization_test.rb
|
@@ -345,26 +345,32 @@ files:
|
|
345
345
|
- test/validations_test.rb
|
346
346
|
- test/xml_serialization_test.rb
|
347
347
|
- examples/associations.png
|
348
|
-
|
349
|
-
|
348
|
+
has_rdoc: true
|
349
|
+
homepage: http://www.rubyonrails.org
|
350
|
+
post_install_message:
|
350
351
|
rdoc_options:
|
351
352
|
- --main
|
352
353
|
- README
|
353
|
-
|
354
|
-
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
354
|
+
require_paths:
|
355
|
+
- lib
|
356
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
357
|
+
requirements:
|
358
|
+
- - ">="
|
359
|
+
- !ruby/object:Gem::Version
|
360
|
+
version: "0"
|
361
|
+
version:
|
362
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
363
|
+
requirements:
|
364
|
+
- - ">="
|
365
|
+
- !ruby/object:Gem::Version
|
366
|
+
version: "0"
|
367
|
+
version:
|
359
368
|
requirements: []
|
360
369
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
- !ruby/object:Gem::Version
|
369
|
-
version: 2.0.1
|
370
|
-
version:
|
370
|
+
rubyforge_project: activerecord
|
371
|
+
rubygems_version: 1.0.0
|
372
|
+
signing_key:
|
373
|
+
specification_version: 2
|
374
|
+
summary: Implements the ActiveRecord pattern for ORM.
|
375
|
+
test_files: []
|
376
|
+
|
File without changes
|