activerecord 1.14.4 → 1.15.0
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 +400 -1
- data/README +2 -2
- data/RUNNING_UNIT_TESTS +21 -3
- data/Rakefile +55 -10
- data/lib/active_record.rb +10 -4
- data/lib/active_record/acts/list.rb +15 -4
- data/lib/active_record/acts/nested_set.rb +11 -12
- data/lib/active_record/acts/tree.rb +13 -14
- data/lib/active_record/aggregations.rb +46 -22
- data/lib/active_record/associations.rb +213 -162
- data/lib/active_record/associations/association_collection.rb +45 -15
- data/lib/active_record/associations/association_proxy.rb +32 -13
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +18 -18
- data/lib/active_record/associations/has_many_association.rb +37 -17
- data/lib/active_record/associations/has_many_through_association.rb +120 -30
- data/lib/active_record/associations/has_one_association.rb +1 -1
- data/lib/active_record/attribute_methods.rb +75 -0
- data/lib/active_record/base.rb +282 -203
- data/lib/active_record/calculations.rb +95 -54
- data/lib/active_record/callbacks.rb +13 -24
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +12 -1
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb.rej +21 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +30 -4
- data/lib/active_record/connection_adapters/abstract/quoting.rb +16 -9
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +121 -37
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +55 -23
- data/lib/active_record/connection_adapters/abstract_adapter.rb +8 -0
- data/lib/active_record/connection_adapters/db2_adapter.rb +1 -11
- data/lib/active_record/connection_adapters/firebird_adapter.rb +364 -50
- data/lib/active_record/connection_adapters/frontbase_adapter.rb +861 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +86 -33
- data/lib/active_record/connection_adapters/openbase_adapter.rb +4 -3
- data/lib/active_record/connection_adapters/oracle_adapter.rb +151 -127
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +125 -48
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +38 -10
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +183 -155
- data/lib/active_record/connection_adapters/sybase_adapter.rb +190 -212
- data/lib/active_record/deprecated_associations.rb +24 -10
- data/lib/active_record/deprecated_finders.rb +4 -1
- data/lib/active_record/fixtures.rb +37 -23
- data/lib/active_record/locking/optimistic.rb +106 -0
- data/lib/active_record/locking/pessimistic.rb +77 -0
- data/lib/active_record/migration.rb +8 -5
- data/lib/active_record/observer.rb +73 -34
- data/lib/active_record/reflection.rb +21 -7
- data/lib/active_record/schema_dumper.rb +33 -5
- data/lib/active_record/timestamp.rb +23 -34
- data/lib/active_record/transactions.rb +37 -30
- data/lib/active_record/validations.rb +46 -30
- data/lib/active_record/vendor/mysql.rb +20 -5
- data/lib/active_record/version.rb +2 -2
- data/lib/active_record/wrappings.rb +1 -2
- data/lib/active_record/xml_serialization.rb +308 -0
- data/test/aaa_create_tables_test.rb +5 -1
- data/test/abstract_unit.rb +18 -8
- data/test/{active_schema_mysql.rb → active_schema_test_mysql.rb} +2 -2
- data/test/adapter_test.rb +9 -7
- data/test/adapter_test_sqlserver.rb +81 -0
- data/test/aggregations_test.rb +29 -0
- data/test/{association_callbacks_test.rb → associations/callbacks_test.rb} +10 -8
- data/test/{associations_cascaded_eager_loading_test.rb → associations/cascaded_eager_loading_test.rb} +35 -3
- data/test/{associations_go_eager_test.rb → associations/eager_test.rb} +36 -2
- data/test/{associations_extensions_test.rb → associations/extension_test.rb} +5 -0
- data/test/{associations_join_model_test.rb → associations/join_model_test.rb} +118 -8
- data/test/associations_test.rb +339 -45
- data/test/attribute_methods_test.rb +49 -0
- data/test/base_test.rb +321 -67
- data/test/calculations_test.rb +48 -10
- data/test/callbacks_test.rb +13 -0
- data/test/connection_test_firebird.rb +8 -0
- data/test/connections/native_db2/connection.rb +18 -17
- data/test/connections/native_firebird/connection.rb +19 -17
- data/test/connections/native_frontbase/connection.rb +27 -0
- data/test/connections/native_mysql/connection.rb +18 -15
- data/test/connections/native_openbase/connection.rb +14 -15
- data/test/connections/native_oracle/connection.rb +16 -12
- data/test/connections/native_postgresql/connection.rb +16 -17
- data/test/connections/native_sqlite/connection.rb +3 -6
- data/test/connections/native_sqlite3/connection.rb +3 -6
- data/test/connections/native_sqlserver/connection.rb +16 -17
- data/test/connections/native_sqlserver_odbc/connection.rb +18 -19
- data/test/connections/native_sybase/connection.rb +16 -17
- data/test/datatype_test_postgresql.rb +52 -0
- data/test/defaults_test.rb +52 -10
- data/test/deprecated_associations_test.rb +151 -107
- data/test/deprecated_finder_test.rb +83 -66
- data/test/empty_date_time_test.rb +25 -0
- data/test/finder_test.rb +118 -11
- data/test/fixtures/accounts.yml +6 -1
- data/test/fixtures/author.rb +27 -4
- data/test/fixtures/categorizations.yml +8 -2
- data/test/fixtures/category.rb +1 -2
- data/test/fixtures/comments.yml +0 -6
- data/test/fixtures/companies.yml +6 -1
- data/test/fixtures/company.rb +23 -1
- data/test/fixtures/company_in_module.rb +8 -10
- data/test/fixtures/customer.rb +2 -2
- data/test/fixtures/customers.yml +9 -0
- data/test/fixtures/db_definitions/db2.drop.sql +1 -0
- data/test/fixtures/db_definitions/db2.sql +9 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +3 -0
- data/test/fixtures/db_definitions/firebird.sql +13 -1
- data/test/fixtures/db_definitions/frontbase.drop.sql +31 -0
- data/test/fixtures/db_definitions/frontbase.sql +262 -0
- data/test/fixtures/db_definitions/frontbase2.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase2.sql +4 -0
- data/test/fixtures/db_definitions/mysql.drop.sql +1 -0
- data/test/fixtures/db_definitions/mysql.sql +23 -14
- data/test/fixtures/db_definitions/openbase.sql +13 -1
- data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle.sql +29 -2
- data/test/fixtures/db_definitions/postgresql.drop.sql +3 -1
- data/test/fixtures/db_definitions/postgresql.sql +13 -3
- data/test/fixtures/db_definitions/schema.rb +29 -1
- data/test/fixtures/db_definitions/sqlite.drop.sql +1 -0
- data/test/fixtures/db_definitions/sqlite.sql +12 -3
- data/test/fixtures/db_definitions/sqlserver.drop.sql +3 -0
- data/test/fixtures/db_definitions/sqlserver.sql +35 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +2 -0
- data/test/fixtures/db_definitions/sybase.sql +13 -4
- data/test/fixtures/developer.rb +12 -0
- data/test/fixtures/edge.rb +5 -0
- data/test/fixtures/edges.yml +6 -0
- data/test/fixtures/funny_jokes.yml +3 -7
- data/test/fixtures/migrations_with_decimal/1_give_me_big_numbers.rb +15 -0
- data/test/fixtures/migrations_with_missing_versions/1000_people_have_middle_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/1_people_have_last_names.rb +9 -0
- data/test/fixtures/migrations_with_missing_versions/3_we_need_reminders.rb +12 -0
- data/test/fixtures/migrations_with_missing_versions/4_innocent_jointable.rb +12 -0
- data/test/fixtures/mixin.rb +15 -0
- data/test/fixtures/mixins.yml +38 -0
- data/test/fixtures/post.rb +3 -2
- data/test/fixtures/project.rb +3 -1
- data/test/fixtures/topic.rb +6 -1
- data/test/fixtures/topics.yml +4 -4
- data/test/fixtures/vertex.rb +9 -0
- data/test/fixtures/vertices.yml +4 -0
- data/test/fixtures_test.rb +45 -0
- data/test/inheritance_test.rb +67 -6
- data/test/lifecycle_test.rb +40 -19
- data/test/locking_test.rb +170 -26
- data/test/method_scoping_test.rb +2 -2
- data/test/migration_test.rb +387 -110
- data/test/migration_test_firebird.rb +124 -0
- data/test/mixin_nested_set_test.rb +14 -2
- data/test/mixin_test.rb +56 -18
- data/test/modules_test.rb +8 -2
- data/test/multiple_db_test.rb +2 -2
- data/test/pk_test.rb +1 -0
- data/test/reflection_test.rb +8 -2
- data/test/schema_authorization_test_postgresql.rb +75 -0
- data/test/schema_dumper_test.rb +40 -4
- data/test/table_name_test_sqlserver.rb +23 -0
- data/test/threaded_connections_test.rb +19 -16
- data/test/transactions_test.rb +86 -72
- data/test/validations_test.rb +126 -56
- data/test/xml_serialization_test.rb +125 -0
- metadata +45 -11
- data/lib/active_record/locking.rb +0 -79
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'abstract_unit'
|
2
|
+
|
3
|
+
class AttributeMethodsTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@old_suffixes = ActiveRecord::Base.send(:attribute_method_suffixes).dup
|
6
|
+
@target = Class.new(ActiveRecord::Base)
|
7
|
+
@target.table_name = 'topics'
|
8
|
+
end
|
9
|
+
|
10
|
+
def teardown
|
11
|
+
ActiveRecord::Base.send(:attribute_method_suffixes).clear
|
12
|
+
ActiveRecord::Base.attribute_method_suffix *@old_suffixes
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
def test_match_attribute_method_query_returns_match_data
|
17
|
+
assert_not_nil md = @target.match_attribute_method?('title=')
|
18
|
+
assert_equal 'title', md.pre_match
|
19
|
+
assert_equal ['='], md.captures
|
20
|
+
|
21
|
+
%w(_hello_world ist! _maybe?).each do |suffix|
|
22
|
+
@target.class_eval "def attribute#{suffix}(*args) args end"
|
23
|
+
@target.attribute_method_suffix suffix
|
24
|
+
|
25
|
+
assert_not_nil md = @target.match_attribute_method?("title#{suffix}")
|
26
|
+
assert_equal 'title', md.pre_match
|
27
|
+
assert_equal [suffix], md.captures
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_declared_attribute_method_affects_respond_to_and_method_missing
|
32
|
+
topic = @target.new(:title => 'Budget')
|
33
|
+
assert topic.respond_to?('title')
|
34
|
+
assert_equal 'Budget', topic.title
|
35
|
+
assert !topic.respond_to?('title_hello_world')
|
36
|
+
assert_raise(NoMethodError) { topic.title_hello_world }
|
37
|
+
|
38
|
+
%w(_hello_world _it! _candidate= able?).each do |suffix|
|
39
|
+
@target.class_eval "def attribute#{suffix}(*args) args end"
|
40
|
+
@target.attribute_method_suffix suffix
|
41
|
+
|
42
|
+
meth = "title#{suffix}"
|
43
|
+
assert topic.respond_to?(meth)
|
44
|
+
assert_equal ['title'], topic.send(meth)
|
45
|
+
assert_equal ['title', 'a'], topic.send(meth, 'a')
|
46
|
+
assert_equal ['title', 1, 2, 3], topic.send(meth, 1, 2, 3)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/test/base_test.rb
CHANGED
@@ -10,10 +10,18 @@ require 'fixtures/auto_id'
|
|
10
10
|
require 'fixtures/column_name'
|
11
11
|
require 'fixtures/subscriber'
|
12
12
|
require 'fixtures/keyboard'
|
13
|
+
require 'fixtures/post'
|
13
14
|
|
14
15
|
class Category < ActiveRecord::Base; end
|
15
16
|
class Smarts < ActiveRecord::Base; end
|
16
|
-
class CreditCard < ActiveRecord::Base
|
17
|
+
class CreditCard < ActiveRecord::Base
|
18
|
+
class PinNumber < ActiveRecord::Base
|
19
|
+
class CvvCode < ActiveRecord::Base; end
|
20
|
+
class SubCvvCode < CvvCode; end
|
21
|
+
end
|
22
|
+
class SubPinNumber < PinNumber; end
|
23
|
+
class Brand < Category; end
|
24
|
+
end
|
17
25
|
class MasterCreditCard < ActiveRecord::Base; end
|
18
26
|
class Post < ActiveRecord::Base; end
|
19
27
|
class Computer < ActiveRecord::Base; end
|
@@ -21,8 +29,9 @@ class NonExistentTable < ActiveRecord::Base; end
|
|
21
29
|
class TestOracleDefault < ActiveRecord::Base; end
|
22
30
|
|
23
31
|
class LoosePerson < ActiveRecord::Base
|
24
|
-
|
32
|
+
self.table_name = 'people'
|
25
33
|
self.abstract_class = true
|
34
|
+
attr_protected :credit_rating, :administrator
|
26
35
|
end
|
27
36
|
|
28
37
|
class LooseDescendant < LoosePerson
|
@@ -30,6 +39,7 @@ class LooseDescendant < LoosePerson
|
|
30
39
|
end
|
31
40
|
|
32
41
|
class TightPerson < ActiveRecord::Base
|
42
|
+
self.table_name = 'people'
|
33
43
|
attr_accessible :name, :address
|
34
44
|
end
|
35
45
|
|
@@ -44,7 +54,7 @@ class Task < ActiveRecord::Base
|
|
44
54
|
end
|
45
55
|
|
46
56
|
class BasicsTest < Test::Unit::TestCase
|
47
|
-
fixtures :topics, :companies, :developers, :projects, :computers
|
57
|
+
fixtures :topics, :companies, :developers, :projects, :computers, :accounts
|
48
58
|
|
49
59
|
def test_table_exists
|
50
60
|
assert !NonExistentTable.table_exists?
|
@@ -59,7 +69,7 @@ class BasicsTest < Test::Unit::TestCase
|
|
59
69
|
assert_equal("Jason", topic.author_name)
|
60
70
|
assert_equal(topics(:first).author_email_address, Topic.find(1).author_email_address)
|
61
71
|
end
|
62
|
-
|
72
|
+
|
63
73
|
def test_integers_as_nil
|
64
74
|
test = AutoId.create('value' => '')
|
65
75
|
assert_nil AutoId.find(test.id).value
|
@@ -142,8 +152,20 @@ class BasicsTest < Test::Unit::TestCase
|
|
142
152
|
def test_save!
|
143
153
|
topic = Topic.new(:title => "New Topic")
|
144
154
|
assert topic.save!
|
145
|
-
end
|
146
155
|
|
156
|
+
reply = Reply.new
|
157
|
+
assert_raise(ActiveRecord::RecordInvalid) { reply.save! }
|
158
|
+
end
|
159
|
+
|
160
|
+
def test_save_null_string_attributes
|
161
|
+
topic = Topic.find(1)
|
162
|
+
topic.attributes = { "title" => "null", "author_name" => "null" }
|
163
|
+
topic.save!
|
164
|
+
topic.reload
|
165
|
+
assert_equal("null", topic.title)
|
166
|
+
assert_equal("null", topic.author_name)
|
167
|
+
end
|
168
|
+
|
147
169
|
def test_hashes_not_mangled
|
148
170
|
new_topic = { :title => "New Topic" }
|
149
171
|
new_topic_values = { :title => "AnotherTopic" }
|
@@ -315,23 +337,22 @@ class BasicsTest < Test::Unit::TestCase
|
|
315
337
|
Time, Topic.find(1).written_on,
|
316
338
|
"The written_on attribute should be of the Time class"
|
317
339
|
)
|
340
|
+
|
341
|
+
# For adapters which support microsecond resolution.
|
342
|
+
if current_adapter?(:PostgreSQLAdapter)
|
343
|
+
assert_equal 11, Topic.find(1).written_on.sec
|
344
|
+
assert_equal 223300, Topic.find(1).written_on.usec
|
345
|
+
assert_equal 9900, Topic.find(2).written_on.usec
|
346
|
+
end
|
318
347
|
end
|
319
|
-
|
348
|
+
|
320
349
|
def test_destroy
|
321
|
-
topic = Topic.
|
322
|
-
topic.
|
323
|
-
topic.
|
324
|
-
topic.save
|
325
|
-
topic.destroy
|
350
|
+
topic = Topic.find(1)
|
351
|
+
assert_equal topic, topic.destroy, 'topic.destroy did not return self'
|
352
|
+
assert topic.frozen?, 'topic not frozen after destroy'
|
326
353
|
assert_raise(ActiveRecord::RecordNotFound) { Topic.find(topic.id) }
|
327
354
|
end
|
328
|
-
|
329
|
-
def test_destroy_returns_self
|
330
|
-
topic = Topic.new("title" => "Yet Another Title")
|
331
|
-
assert topic.save
|
332
|
-
assert_equal topic, topic.destroy, "destroy did not return destroyed object"
|
333
|
-
end
|
334
|
-
|
355
|
+
|
335
356
|
def test_record_not_found_exception
|
336
357
|
assert_raises(ActiveRecord::RecordNotFound) { topicReloaded = Topic.find(99999) }
|
337
358
|
end
|
@@ -368,21 +389,33 @@ class BasicsTest < Test::Unit::TestCase
|
|
368
389
|
end
|
369
390
|
|
370
391
|
def test_table_name_guesses
|
392
|
+
classes = [Category, Smarts, CreditCard, CreditCard::PinNumber, CreditCard::PinNumber::CvvCode, CreditCard::SubPinNumber, CreditCard::Brand, MasterCreditCard]
|
393
|
+
|
371
394
|
assert_equal "topics", Topic.table_name
|
372
|
-
|
395
|
+
|
373
396
|
assert_equal "categories", Category.table_name
|
374
397
|
assert_equal "smarts", Smarts.table_name
|
375
398
|
assert_equal "credit_cards", CreditCard.table_name
|
399
|
+
assert_equal "credit_card_pin_numbers", CreditCard::PinNumber.table_name
|
400
|
+
assert_equal "credit_card_pin_number_cvv_codes", CreditCard::PinNumber::CvvCode.table_name
|
401
|
+
assert_equal "credit_card_pin_numbers", CreditCard::SubPinNumber.table_name
|
402
|
+
assert_equal "categories", CreditCard::Brand.table_name
|
376
403
|
assert_equal "master_credit_cards", MasterCreditCard.table_name
|
377
404
|
|
378
405
|
ActiveRecord::Base.pluralize_table_names = false
|
379
|
-
|
406
|
+
classes.each(&:reset_table_name)
|
407
|
+
|
380
408
|
assert_equal "category", Category.table_name
|
381
409
|
assert_equal "smarts", Smarts.table_name
|
382
410
|
assert_equal "credit_card", CreditCard.table_name
|
411
|
+
assert_equal "credit_card_pin_number", CreditCard::PinNumber.table_name
|
412
|
+
assert_equal "credit_card_pin_number_cvv_code", CreditCard::PinNumber::CvvCode.table_name
|
413
|
+
assert_equal "credit_card_pin_number", CreditCard::SubPinNumber.table_name
|
414
|
+
assert_equal "category", CreditCard::Brand.table_name
|
383
415
|
assert_equal "master_credit_card", MasterCreditCard.table_name
|
416
|
+
|
384
417
|
ActiveRecord::Base.pluralize_table_names = true
|
385
|
-
|
418
|
+
classes.each(&:reset_table_name)
|
386
419
|
|
387
420
|
ActiveRecord::Base.table_name_prefix = "test_"
|
388
421
|
Category.reset_table_name
|
@@ -410,8 +443,9 @@ class BasicsTest < Test::Unit::TestCase
|
|
410
443
|
ActiveRecord::Base.table_name_suffix = ""
|
411
444
|
Category.reset_table_name
|
412
445
|
assert_equal "category", Category.table_name
|
446
|
+
|
413
447
|
ActiveRecord::Base.pluralize_table_names = true
|
414
|
-
|
448
|
+
classes.each(&:reset_table_name)
|
415
449
|
end
|
416
450
|
|
417
451
|
def test_destroy_all
|
@@ -439,18 +473,18 @@ class BasicsTest < Test::Unit::TestCase
|
|
439
473
|
|
440
474
|
def test_increment_counter
|
441
475
|
Topic.increment_counter("replies_count", 1)
|
442
|
-
assert_equal
|
476
|
+
assert_equal 2, Topic.find(1).replies_count
|
443
477
|
|
444
478
|
Topic.increment_counter("replies_count", 1)
|
445
|
-
assert_equal
|
479
|
+
assert_equal 3, Topic.find(1).replies_count
|
446
480
|
end
|
447
481
|
|
448
482
|
def test_decrement_counter
|
449
483
|
Topic.decrement_counter("replies_count", 2)
|
450
|
-
assert_equal 1, Topic.find(2).replies_count
|
484
|
+
assert_equal -1, Topic.find(2).replies_count
|
451
485
|
|
452
486
|
Topic.decrement_counter("replies_count", 2)
|
453
|
-
assert_equal
|
487
|
+
assert_equal -2, Topic.find(2).replies_count
|
454
488
|
end
|
455
489
|
|
456
490
|
def test_update_all
|
@@ -549,16 +583,29 @@ class BasicsTest < Test::Unit::TestCase
|
|
549
583
|
end
|
550
584
|
end
|
551
585
|
|
552
|
-
|
553
|
-
|
554
|
-
|
586
|
+
# Oracle, SQLServer, and Sybase do not have a TIME datatype.
|
587
|
+
unless current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
|
588
|
+
def test_utc_as_time_zone
|
589
|
+
Topic.default_timezone = :utc
|
590
|
+
attributes = { "bonus_time" => "5:42:00AM" }
|
591
|
+
topic = Topic.find(1)
|
592
|
+
topic.attributes = attributes
|
593
|
+
assert_equal Time.utc(2000, 1, 1, 5, 42, 0), topic.bonus_time
|
594
|
+
Topic.default_timezone = :local
|
595
|
+
end
|
555
596
|
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
597
|
+
def test_utc_as_time_zone_and_new
|
598
|
+
Topic.default_timezone = :utc
|
599
|
+
attributes = { "bonus_time(1i)"=>"2000",
|
600
|
+
"bonus_time(2i)"=>"1",
|
601
|
+
"bonus_time(3i)"=>"1",
|
602
|
+
"bonus_time(4i)"=>"10",
|
603
|
+
"bonus_time(5i)"=>"35",
|
604
|
+
"bonus_time(6i)"=>"50" }
|
605
|
+
topic = Topic.new(attributes)
|
606
|
+
assert_equal Time.utc(2000, 1, 1, 10, 35, 50), topic.bonus_time
|
607
|
+
Topic.default_timezone = :local
|
608
|
+
end
|
562
609
|
end
|
563
610
|
|
564
611
|
def test_default_values_on_empty_strings
|
@@ -614,6 +661,40 @@ class BasicsTest < Test::Unit::TestCase
|
|
614
661
|
assert !Topic.find(1).approved?
|
615
662
|
end
|
616
663
|
|
664
|
+
def test_update_attributes
|
665
|
+
topic = Topic.find(1)
|
666
|
+
assert !topic.approved?
|
667
|
+
assert_equal "The First Topic", topic.title
|
668
|
+
|
669
|
+
topic.update_attributes("approved" => true, "title" => "The First Topic Updated")
|
670
|
+
topic.reload
|
671
|
+
assert topic.approved?
|
672
|
+
assert_equal "The First Topic Updated", topic.title
|
673
|
+
|
674
|
+
topic.update_attributes(:approved => false, :title => "The First Topic")
|
675
|
+
topic.reload
|
676
|
+
assert !topic.approved?
|
677
|
+
assert_equal "The First Topic", topic.title
|
678
|
+
end
|
679
|
+
|
680
|
+
def test_update_attributes!
|
681
|
+
reply = Reply.find(2)
|
682
|
+
assert_equal "The Second Topic's of the day", reply.title
|
683
|
+
assert_equal "Have a nice day", reply.content
|
684
|
+
|
685
|
+
reply.update_attributes!("title" => "The Second Topic's of the day updated", "content" => "Have a nice evening")
|
686
|
+
reply.reload
|
687
|
+
assert_equal "The Second Topic's of the day updated", reply.title
|
688
|
+
assert_equal "Have a nice evening", reply.content
|
689
|
+
|
690
|
+
reply.update_attributes!(:title => "The Second Topic's of the day", :content => "Have a nice day")
|
691
|
+
reply.reload
|
692
|
+
assert_equal "The Second Topic's of the day", reply.title
|
693
|
+
assert_equal "Have a nice day", reply.content
|
694
|
+
|
695
|
+
assert_raise(ActiveRecord::RecordInvalid) { reply.update_attributes!(:title => nil, :content => "Have a nice evening") }
|
696
|
+
end
|
697
|
+
|
617
698
|
def test_mass_assignment_protection
|
618
699
|
firm = Firm.new
|
619
700
|
firm.attributes = { "name" => "Next Angle", "rating" => 5 }
|
@@ -732,8 +813,8 @@ class BasicsTest < Test::Unit::TestCase
|
|
732
813
|
end
|
733
814
|
|
734
815
|
def test_attributes_on_dummy_time
|
735
|
-
# Oracle
|
736
|
-
return true if current_adapter?(:SQLServerAdapter
|
816
|
+
# Oracle, SQL Server, and Sybase do not have a TIME datatype.
|
817
|
+
return true if current_adapter?(:SQLServerAdapter, :OracleAdapter, :SybaseAdapter)
|
737
818
|
|
738
819
|
attributes = {
|
739
820
|
"bonus_time" => "5:42:00AM"
|
@@ -903,12 +984,44 @@ class BasicsTest < Test::Unit::TestCase
|
|
903
984
|
end
|
904
985
|
end
|
905
986
|
|
987
|
+
class NumericData < ActiveRecord::Base
|
988
|
+
self.table_name = 'numeric_data'
|
989
|
+
end
|
990
|
+
|
991
|
+
def test_numeric_fields
|
992
|
+
m = NumericData.new(
|
993
|
+
:bank_balance => 1586.43,
|
994
|
+
:big_bank_balance => BigDecimal("1000234000567.95"),
|
995
|
+
:world_population => 6000000000,
|
996
|
+
:my_house_population => 3
|
997
|
+
)
|
998
|
+
assert m.save
|
999
|
+
|
1000
|
+
m1 = NumericData.find(m.id)
|
1001
|
+
assert_not_nil m1
|
1002
|
+
|
1003
|
+
# As with migration_test.rb, we should make world_population >= 2**62
|
1004
|
+
# to cover 64-bit platforms and test it is a Bignum, but the main thing
|
1005
|
+
# is that it's an Integer.
|
1006
|
+
assert_kind_of Integer, m1.world_population
|
1007
|
+
assert_equal 6000000000, m1.world_population
|
1008
|
+
|
1009
|
+
assert_kind_of Fixnum, m1.my_house_population
|
1010
|
+
assert_equal 3, m1.my_house_population
|
1011
|
+
|
1012
|
+
assert_kind_of BigDecimal, m1.bank_balance
|
1013
|
+
assert_equal BigDecimal("1586.43"), m1.bank_balance
|
1014
|
+
|
1015
|
+
assert_kind_of BigDecimal, m1.big_bank_balance
|
1016
|
+
assert_equal BigDecimal("1000234000567.95"), m1.big_bank_balance
|
1017
|
+
end
|
1018
|
+
|
906
1019
|
def test_auto_id
|
907
1020
|
auto = AutoId.new
|
908
1021
|
auto.save
|
909
1022
|
assert (auto.id > 0)
|
910
1023
|
end
|
911
|
-
|
1024
|
+
|
912
1025
|
def quote_column_name(name)
|
913
1026
|
"<#{name}>"
|
914
1027
|
end
|
@@ -923,13 +1036,9 @@ class BasicsTest < Test::Unit::TestCase
|
|
923
1036
|
end
|
924
1037
|
|
925
1038
|
def test_sql_injection_via_find
|
926
|
-
assert_raises(ActiveRecord::RecordNotFound) do
|
1039
|
+
assert_raises(ActiveRecord::RecordNotFound, ActiveRecord::StatementInvalid) do
|
927
1040
|
Topic.find("123456 OR id > 0")
|
928
1041
|
end
|
929
|
-
|
930
|
-
assert_raises(ActiveRecord::RecordNotFound) do
|
931
|
-
Topic.find(";;; this should raise an RecordNotFound error")
|
932
|
-
end
|
933
1042
|
end
|
934
1043
|
|
935
1044
|
def test_column_name_properly_quoted
|
@@ -942,6 +1051,14 @@ class BasicsTest < Test::Unit::TestCase
|
|
942
1051
|
assert_equal(41, c2.references)
|
943
1052
|
end
|
944
1053
|
|
1054
|
+
def test_quoting_arrays
|
1055
|
+
replies = Reply.find(:all, :conditions => [ "id IN (?)", topics(:first).replies.collect(&:id) ])
|
1056
|
+
assert_equal topics(:first).replies.size, replies.size
|
1057
|
+
|
1058
|
+
replies = Reply.find(:all, :conditions => [ "id IN (?)", [] ])
|
1059
|
+
assert_equal 0, replies.size
|
1060
|
+
end
|
1061
|
+
|
945
1062
|
MyObject = Struct.new :attribute1, :attribute2
|
946
1063
|
|
947
1064
|
def test_serialized_attribute
|
@@ -970,6 +1087,18 @@ class BasicsTest < Test::Unit::TestCase
|
|
970
1087
|
assert_equal author_name, Topic.find(topic.id).author_name
|
971
1088
|
end
|
972
1089
|
|
1090
|
+
def test_quote_chars
|
1091
|
+
str = 'The Narrator'
|
1092
|
+
topic = Topic.create(:author_name => str)
|
1093
|
+
assert_equal str, topic.author_name
|
1094
|
+
|
1095
|
+
assert_kind_of ActiveSupport::Multibyte::Chars, str.chars
|
1096
|
+
topic = Topic.find_by_author_name(str.chars)
|
1097
|
+
|
1098
|
+
assert_kind_of Topic, topic
|
1099
|
+
assert_equal str, topic.author_name, "The right topic should have been found by name even with name passed as Chars"
|
1100
|
+
end
|
1101
|
+
|
973
1102
|
def test_class_level_destroy
|
974
1103
|
should_be_destroyed_reply = Reply.create("title" => "hello", "content" => "world")
|
975
1104
|
Topic.find(1).replies << should_be_destroyed_reply
|
@@ -989,12 +1118,12 @@ class BasicsTest < Test::Unit::TestCase
|
|
989
1118
|
end
|
990
1119
|
|
991
1120
|
def test_increment_attribute
|
992
|
-
assert_equal
|
1121
|
+
assert_equal 1, topics(:first).replies_count
|
993
1122
|
topics(:first).increment! :replies_count
|
994
|
-
assert_equal
|
1123
|
+
assert_equal 2, topics(:first, :reload).replies_count
|
995
1124
|
|
996
1125
|
topics(:first).increment(:replies_count).increment!(:replies_count)
|
997
|
-
assert_equal
|
1126
|
+
assert_equal 4, topics(:first, :reload).replies_count
|
998
1127
|
end
|
999
1128
|
|
1000
1129
|
def test_increment_nil_attribute
|
@@ -1005,13 +1134,13 @@ class BasicsTest < Test::Unit::TestCase
|
|
1005
1134
|
|
1006
1135
|
def test_decrement_attribute
|
1007
1136
|
topics(:first).increment(:replies_count).increment!(:replies_count)
|
1008
|
-
assert_equal
|
1137
|
+
assert_equal 3, topics(:first).replies_count
|
1009
1138
|
|
1010
1139
|
topics(:first).decrement!(:replies_count)
|
1011
|
-
assert_equal
|
1140
|
+
assert_equal 2, topics(:first, :reload).replies_count
|
1012
1141
|
|
1013
1142
|
topics(:first).decrement(:replies_count).decrement!(:replies_count)
|
1014
|
-
assert_equal
|
1143
|
+
assert_equal 0, topics(:first, :reload).replies_count
|
1015
1144
|
end
|
1016
1145
|
|
1017
1146
|
def test_toggle_attribute
|
@@ -1091,7 +1220,7 @@ class BasicsTest < Test::Unit::TestCase
|
|
1091
1220
|
def test_count_with_join
|
1092
1221
|
res = Post.count_by_sql "SELECT COUNT(*) FROM posts LEFT JOIN comments ON posts.id=comments.post_id WHERE posts.#{QUOTED_TYPE} = 'Post'"
|
1093
1222
|
res2 = nil
|
1094
|
-
|
1223
|
+
assert_deprecated 'count' do
|
1095
1224
|
res2 = Post.count("posts.#{QUOTED_TYPE} = 'Post'",
|
1096
1225
|
"LEFT JOIN comments ON posts.id=comments.post_id")
|
1097
1226
|
end
|
@@ -1104,21 +1233,21 @@ class BasicsTest < Test::Unit::TestCase
|
|
1104
1233
|
end
|
1105
1234
|
assert_equal res, res3
|
1106
1235
|
|
1107
|
-
res4 = Post.count_by_sql "SELECT COUNT(p.id) FROM posts p, comments
|
1236
|
+
res4 = Post.count_by_sql "SELECT COUNT(p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
|
1108
1237
|
res5 = nil
|
1109
1238
|
assert_nothing_raised do
|
1110
|
-
res5 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=
|
1111
|
-
:joins => "p, comments
|
1239
|
+
res5 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
|
1240
|
+
:joins => "p, comments co",
|
1112
1241
|
:select => "p.id")
|
1113
1242
|
end
|
1114
1243
|
|
1115
1244
|
assert_equal res4, res5
|
1116
1245
|
|
1117
|
-
res6 = Post.count_by_sql "SELECT COUNT(DISTINCT p.id) FROM posts p, comments
|
1246
|
+
res6 = Post.count_by_sql "SELECT COUNT(DISTINCT p.id) FROM posts p, comments co WHERE p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id"
|
1118
1247
|
res7 = nil
|
1119
1248
|
assert_nothing_raised do
|
1120
|
-
res7 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=
|
1121
|
-
:joins => "p, comments
|
1249
|
+
res7 = Post.count(:conditions => "p.#{QUOTED_TYPE} = 'Post' AND p.id=co.post_id",
|
1250
|
+
:joins => "p, comments co",
|
1122
1251
|
:select => "p.id",
|
1123
1252
|
:distinct => true)
|
1124
1253
|
end
|
@@ -1174,13 +1303,104 @@ class BasicsTest < Test::Unit::TestCase
|
|
1174
1303
|
assert_equal Developer.count, developers.size
|
1175
1304
|
end
|
1176
1305
|
|
1177
|
-
def
|
1306
|
+
def test_scoped_find_order
|
1307
|
+
# Test order in scope
|
1308
|
+
scoped_developers = Developer.with_scope(:find => { :limit => 1, :order => 'salary DESC' }) do
|
1309
|
+
Developer.find(:all)
|
1310
|
+
end
|
1311
|
+
assert_equal 'Jamis', scoped_developers.first.name
|
1312
|
+
assert scoped_developers.include?(developers(:jamis))
|
1313
|
+
# Test scope without order and order in find
|
1314
|
+
scoped_developers = Developer.with_scope(:find => { :limit => 1 }) do
|
1315
|
+
Developer.find(:all, :order => 'salary DESC')
|
1316
|
+
end
|
1317
|
+
# Test scope order + find order, find has priority
|
1318
|
+
scoped_developers = Developer.with_scope(:find => { :limit => 3, :order => 'id DESC' }) do
|
1319
|
+
Developer.find(:all, :order => 'salary ASC')
|
1320
|
+
end
|
1321
|
+
assert scoped_developers.include?(developers(:poor_jamis))
|
1322
|
+
assert scoped_developers.include?(developers(:david))
|
1323
|
+
assert scoped_developers.include?(developers(:dev_10))
|
1324
|
+
# Test without scoped find conditions to ensure we get the right thing
|
1325
|
+
developers = Developer.find(:all, :order => 'id', :limit => 1)
|
1326
|
+
assert scoped_developers.include?(developers(:david))
|
1327
|
+
end
|
1328
|
+
|
1329
|
+
def test_scoped_find_limit_offset_including_has_many_association
|
1330
|
+
topics = Topic.with_scope(:find => {:limit => 1, :offset => 1, :include => :replies}) do
|
1331
|
+
Topic.find(:all, :order => "topics.id")
|
1332
|
+
end
|
1333
|
+
assert_equal 1, topics.size
|
1334
|
+
assert_equal 2, topics.first.id
|
1335
|
+
end
|
1336
|
+
|
1337
|
+
def test_scoped_find_order_including_has_many_association
|
1338
|
+
developers = Developer.with_scope(:find => { :order => 'developers.salary DESC', :include => :projects }) do
|
1339
|
+
Developer.find(:all)
|
1340
|
+
end
|
1341
|
+
assert developers.size >= 2
|
1342
|
+
for i in 1...developers.size
|
1343
|
+
assert developers[i-1].salary >= developers[i].salary
|
1344
|
+
end
|
1345
|
+
end
|
1346
|
+
|
1347
|
+
def test_abstract_class
|
1348
|
+
assert !ActiveRecord::Base.abstract_class?
|
1178
1349
|
assert LoosePerson.abstract_class?
|
1179
1350
|
assert !LooseDescendant.abstract_class?
|
1351
|
+
end
|
1352
|
+
|
1353
|
+
def test_base_class
|
1180
1354
|
assert_equal LoosePerson, LoosePerson.base_class
|
1181
1355
|
assert_equal LooseDescendant, LooseDescendant.base_class
|
1182
1356
|
assert_equal TightPerson, TightPerson.base_class
|
1183
1357
|
assert_equal TightPerson, TightDescendant.base_class
|
1358
|
+
|
1359
|
+
assert_equal Post, Post.base_class
|
1360
|
+
assert_equal Post, SpecialPost.base_class
|
1361
|
+
assert_equal Post, StiPost.base_class
|
1362
|
+
assert_equal SubStiPost, SubStiPost.base_class
|
1363
|
+
end
|
1364
|
+
|
1365
|
+
def test_descends_from_active_record
|
1366
|
+
# Tries to call Object.abstract_class?
|
1367
|
+
assert_raise(NoMethodError) do
|
1368
|
+
ActiveRecord::Base.descends_from_active_record?
|
1369
|
+
end
|
1370
|
+
|
1371
|
+
# Abstract subclass of AR::Base.
|
1372
|
+
assert LoosePerson.descends_from_active_record?
|
1373
|
+
|
1374
|
+
# Concrete subclass of an abstract class.
|
1375
|
+
assert LooseDescendant.descends_from_active_record?
|
1376
|
+
|
1377
|
+
# Concrete subclass of AR::Base.
|
1378
|
+
assert TightPerson.descends_from_active_record?
|
1379
|
+
|
1380
|
+
# Concrete subclass of a concrete class but has no type column.
|
1381
|
+
assert TightDescendant.descends_from_active_record?
|
1382
|
+
|
1383
|
+
# Concrete subclass of AR::Base.
|
1384
|
+
assert Post.descends_from_active_record?
|
1385
|
+
|
1386
|
+
# Abstract subclass of a concrete class which has a type column.
|
1387
|
+
# This is pathological, as you'll never have Sub < Abstract < Concrete.
|
1388
|
+
assert !StiPost.descends_from_active_record?
|
1389
|
+
|
1390
|
+
# Concrete subclasses an abstract class which has a type column.
|
1391
|
+
assert !SubStiPost.descends_from_active_record?
|
1392
|
+
end
|
1393
|
+
|
1394
|
+
def test_find_on_abstract_base_class_doesnt_use_type_condition
|
1395
|
+
old_class = LooseDescendant
|
1396
|
+
Object.send :remove_const, :LooseDescendant
|
1397
|
+
|
1398
|
+
descendant = old_class.create!
|
1399
|
+
assert_not_nil LoosePerson.find(descendant.id), "Should have found instance of LooseDescendant when finding abstract LoosePerson: #{descendant.inspect}"
|
1400
|
+
ensure
|
1401
|
+
unless Object.const_defined?(:LooseDescendant)
|
1402
|
+
Object.const_set :LooseDescendant, old_class
|
1403
|
+
end
|
1184
1404
|
end
|
1185
1405
|
|
1186
1406
|
def test_assert_queries
|
@@ -1199,41 +1419,65 @@ class BasicsTest < Test::Unit::TestCase
|
|
1199
1419
|
assert xml.include?(%(<title>The First Topic</title>))
|
1200
1420
|
assert xml.include?(%(<author-name>David</author-name>))
|
1201
1421
|
assert xml.include?(%(<id type="integer">1</id>))
|
1202
|
-
assert xml.include?(%(<replies-count type="integer">
|
1422
|
+
assert xml.include?(%(<replies-count type="integer">1</replies-count>))
|
1203
1423
|
assert xml.include?(%(<written-on type="datetime">#{written_on_in_current_timezone}</written-on>))
|
1204
1424
|
assert xml.include?(%(<content>Have a nice day</content>))
|
1205
1425
|
assert xml.include?(%(<author-email-address>david@loudthinking.com</author-email-address>))
|
1206
|
-
assert xml.
|
1207
|
-
if current_adapter?(:SybaseAdapter
|
1426
|
+
assert xml.match(%(<parent-id type="integer"></parent-id>))
|
1427
|
+
if current_adapter?(:SybaseAdapter, :SQLServerAdapter, :OracleAdapter)
|
1208
1428
|
assert xml.include?(%(<last-read type="datetime">#{last_read_in_current_timezone}</last-read>))
|
1209
1429
|
else
|
1210
1430
|
assert xml.include?(%(<last-read type="date">2004-04-15</last-read>))
|
1211
1431
|
end
|
1212
1432
|
# Oracle and DB2 don't have true boolean or time-only fields
|
1213
|
-
unless current_adapter?(:OracleAdapter
|
1433
|
+
unless current_adapter?(:OracleAdapter, :DB2Adapter)
|
1214
1434
|
assert xml.include?(%(<approved type="boolean">false</approved>)), "Approved should be a boolean"
|
1215
1435
|
assert xml.include?(%(<bonus-time type="datetime">#{bonus_time_in_current_timezone}</bonus-time>))
|
1216
1436
|
end
|
1217
1437
|
end
|
1218
|
-
|
1438
|
+
|
1219
1439
|
def test_to_xml_skipping_attributes
|
1220
|
-
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => :title)
|
1440
|
+
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => [:title, :replies_count])
|
1221
1441
|
assert_equal "<topic>", xml.first(7)
|
1222
1442
|
assert !xml.include?(%(<title>The First Topic</title>))
|
1223
1443
|
assert xml.include?(%(<author-name>David</author-name>))
|
1224
1444
|
|
1225
|
-
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => [
|
1445
|
+
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :except => [:title, :author_name, :replies_count])
|
1226
1446
|
assert !xml.include?(%(<title>The First Topic</title>))
|
1227
1447
|
assert !xml.include?(%(<author-name>David</author-name>))
|
1228
1448
|
end
|
1229
|
-
|
1449
|
+
|
1230
1450
|
def test_to_xml_including_has_many_association
|
1231
|
-
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :include => :replies)
|
1451
|
+
xml = topics(:first).to_xml(:indent => 0, :skip_instruct => true, :include => :replies, :except => :replies_count)
|
1232
1452
|
assert_equal "<topic>", xml.first(7)
|
1233
1453
|
assert xml.include?(%(<replies><reply>))
|
1234
1454
|
assert xml.include?(%(<title>The Second Topic's of the day</title>))
|
1235
1455
|
end
|
1236
1456
|
|
1457
|
+
def test_array_to_xml_including_has_many_association
|
1458
|
+
xml = [ topics(:first), topics(:second) ].to_xml(:indent => 0, :skip_instruct => true, :include => :replies)
|
1459
|
+
assert xml.include?(%(<replies><reply>))
|
1460
|
+
end
|
1461
|
+
|
1462
|
+
def test_array_to_xml_including_methods
|
1463
|
+
xml = [ topics(:first), topics(:second) ].to_xml(:indent => 0, :skip_instruct => true, :methods => [ :topic_id ])
|
1464
|
+
assert xml.include?(%(<topic-id type="integer">#{topics(:first).topic_id}</topic-id>)), xml
|
1465
|
+
assert xml.include?(%(<topic-id type="integer">#{topics(:second).topic_id}</topic-id>)), xml
|
1466
|
+
end
|
1467
|
+
|
1468
|
+
def test_array_to_xml_including_has_one_association
|
1469
|
+
xml = [ companies(:first_firm), companies(:rails_core) ].to_xml(:indent => 0, :skip_instruct => true, :include => :account)
|
1470
|
+
assert xml.include?(companies(:first_firm).account.to_xml(:indent => 0, :skip_instruct => true))
|
1471
|
+
assert xml.include?(companies(:rails_core).account.to_xml(:indent => 0, :skip_instruct => true))
|
1472
|
+
end
|
1473
|
+
|
1474
|
+
def test_array_to_xml_including_belongs_to_association
|
1475
|
+
xml = [ companies(:first_client), companies(:second_client), companies(:another_client) ].to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
|
1476
|
+
assert xml.include?(companies(:first_client).to_xml(:indent => 0, :skip_instruct => true))
|
1477
|
+
assert xml.include?(companies(:second_client).firm.to_xml(:indent => 0, :skip_instruct => true))
|
1478
|
+
assert xml.include?(companies(:another_client).firm.to_xml(:indent => 0, :skip_instruct => true))
|
1479
|
+
end
|
1480
|
+
|
1237
1481
|
def test_to_xml_including_belongs_to_association
|
1238
1482
|
xml = companies(:first_client).to_xml(:indent => 0, :skip_instruct => true, :include => :firm)
|
1239
1483
|
assert !xml.include?("<firm>")
|
@@ -1260,6 +1504,12 @@ class BasicsTest < Test::Unit::TestCase
|
|
1260
1504
|
assert xml.include?(%(<clients><client>))
|
1261
1505
|
end
|
1262
1506
|
|
1507
|
+
def test_to_xml_including_methods
|
1508
|
+
xml = Company.new.to_xml(:methods => :arbitrary_method, :skip_instruct => true)
|
1509
|
+
assert_equal "<company>", xml.first(9)
|
1510
|
+
assert xml.include?(%(<arbitrary-method>I am Jack's profound disappointment</arbitrary-method>))
|
1511
|
+
end
|
1512
|
+
|
1263
1513
|
def test_except_attributes
|
1264
1514
|
assert_equal(
|
1265
1515
|
%w( author_name type id approved replies_count bonus_time written_on content author_email_address parent_id last_read),
|
@@ -1281,6 +1531,10 @@ class BasicsTest < Test::Unit::TestCase
|
|
1281
1531
|
assert_equal 'ActiveRecord::Person', ActiveRecord::Base.send(:type_name_with_module, 'Person')
|
1282
1532
|
assert_equal '::Person', ActiveRecord::Base.send(:type_name_with_module, '::Person')
|
1283
1533
|
end
|
1534
|
+
|
1535
|
+
def test_to_param_should_return_string
|
1536
|
+
assert_kind_of String, Client.find(:first).to_param
|
1537
|
+
end
|
1284
1538
|
|
1285
1539
|
# FIXME: this test ought to run, but it needs to run sandboxed so that it
|
1286
1540
|
# doesn't b0rk the current test environment by undefing everything.
|
@@ -1306,7 +1560,7 @@ class BasicsTest < Test::Unit::TestCase
|
|
1306
1560
|
|
1307
1561
|
private
|
1308
1562
|
def assert_readers(model, exceptions)
|
1309
|
-
expected_readers = Set.new(model.column_names -
|
1563
|
+
expected_readers = Set.new(model.column_names - ['id'])
|
1310
1564
|
expected_readers += expected_readers.map { |col| "#{col}?" }
|
1311
1565
|
expected_readers -= exceptions
|
1312
1566
|
assert_equal expected_readers, model.read_methods
|