activerecord 2.0.5 → 2.1.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 +168 -6
- data/README +27 -22
- data/RUNNING_UNIT_TESTS +7 -4
- data/Rakefile +22 -25
- data/lib/active_record.rb +8 -2
- data/lib/active_record/aggregations.rb +21 -12
- data/lib/active_record/association_preload.rb +277 -0
- data/lib/active_record/associations.rb +481 -295
- data/lib/active_record/associations/association_collection.rb +162 -37
- data/lib/active_record/associations/association_proxy.rb +71 -7
- data/lib/active_record/associations/belongs_to_association.rb +5 -3
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +5 -6
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +12 -64
- data/lib/active_record/associations/has_many_association.rb +8 -73
- data/lib/active_record/associations/has_many_through_association.rb +68 -117
- data/lib/active_record/associations/has_one_association.rb +7 -5
- data/lib/active_record/associations/has_one_through_association.rb +28 -0
- data/lib/active_record/attribute_methods.rb +69 -19
- data/lib/active_record/base.rb +496 -275
- data/lib/active_record/calculations.rb +28 -21
- data/lib/active_record/callbacks.rb +9 -38
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +3 -2
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +2 -2
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +6 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +232 -45
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +141 -27
- data/lib/active_record/connection_adapters/abstract_adapter.rb +9 -13
- data/lib/active_record/connection_adapters/mysql_adapter.rb +57 -24
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +143 -42
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -1
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +18 -10
- data/lib/active_record/dirty.rb +158 -0
- data/lib/active_record/fixtures.rb +121 -156
- data/lib/active_record/locking/optimistic.rb +14 -11
- data/lib/active_record/locking/pessimistic.rb +2 -2
- data/lib/active_record/migration.rb +157 -77
- data/lib/active_record/named_scope.rb +163 -0
- data/lib/active_record/observer.rb +19 -5
- data/lib/active_record/reflection.rb +34 -14
- data/lib/active_record/schema.rb +7 -14
- data/lib/active_record/schema_dumper.rb +4 -4
- data/lib/active_record/serialization.rb +5 -5
- data/lib/active_record/serializers/json_serializer.rb +37 -28
- data/lib/active_record/serializers/xml_serializer.rb +52 -29
- data/lib/active_record/test_case.rb +36 -0
- data/lib/active_record/timestamp.rb +4 -4
- data/lib/active_record/transactions.rb +3 -3
- data/lib/active_record/validations.rb +182 -248
- data/lib/active_record/version.rb +2 -2
- data/test/{fixtures → assets}/example.log +0 -0
- data/test/{fixtures → assets}/flowers.jpg +0 -0
- data/test/cases/aaa_create_tables_test.rb +24 -0
- data/test/cases/active_schema_test_mysql.rb +95 -0
- data/test/cases/active_schema_test_postgresql.rb +24 -0
- data/test/{adapter_test.rb → cases/adapter_test.rb} +15 -14
- data/test/{adapter_test_sqlserver.rb → cases/adapter_test_sqlserver.rb} +95 -95
- data/test/{aggregations_test.rb → cases/aggregations_test.rb} +20 -20
- data/test/{ar_schema_test.rb → cases/ar_schema_test.rb} +6 -6
- data/test/cases/associations/belongs_to_associations_test.rb +412 -0
- data/test/{associations → cases/associations}/callbacks_test.rb +24 -10
- data/test/{associations → cases/associations}/cascaded_eager_loading_test.rb +18 -17
- data/test/cases/associations/eager_load_nested_include_test.rb +83 -0
- data/test/{associations → cases/associations}/eager_singularization_test.rb +5 -5
- data/test/{associations → cases/associations}/eager_test.rb +216 -51
- data/test/{associations → cases/associations}/extension_test.rb +8 -8
- data/test/cases/associations/has_and_belongs_to_many_associations_test.rb +684 -0
- data/test/cases/associations/has_many_associations_test.rb +932 -0
- data/test/cases/associations/has_many_through_associations_test.rb +190 -0
- data/test/cases/associations/has_one_associations_test.rb +323 -0
- data/test/cases/associations/has_one_through_associations_test.rb +74 -0
- data/test/{associations → cases/associations}/inner_join_association_test.rb +20 -20
- data/test/{associations → cases/associations}/join_model_test.rb +175 -35
- data/test/cases/associations_test.rb +262 -0
- data/test/{attribute_methods_test.rb → cases/attribute_methods_test.rb} +103 -11
- data/test/{base_test.rb → cases/base_test.rb} +338 -191
- data/test/{binary_test.rb → cases/binary_test.rb} +6 -4
- data/test/{calculations_test.rb → cases/calculations_test.rb} +35 -23
- data/test/{callbacks_test.rb → cases/callbacks_test.rb} +7 -7
- data/test/{class_inheritable_attributes_test.rb → cases/class_inheritable_attributes_test.rb} +3 -3
- data/test/{column_alias_test.rb → cases/column_alias_test.rb} +3 -3
- data/test/{connection_test_firebird.rb → cases/connection_test_firebird.rb} +2 -2
- data/test/{connection_test_mysql.rb → cases/connection_test_mysql.rb} +2 -2
- data/test/{copy_table_test_sqlite.rb → cases/copy_table_test_sqlite.rb} +13 -13
- data/test/{datatype_test_postgresql.rb → cases/datatype_test_postgresql.rb} +8 -8
- data/test/{date_time_test.rb → cases/date_time_test.rb} +5 -5
- data/test/{default_test_firebird.rb → cases/default_test_firebird.rb} +3 -3
- data/test/{defaults_test.rb → cases/defaults_test.rb} +8 -6
- data/test/{deprecated_finder_test.rb → cases/deprecated_finder_test.rb} +3 -3
- data/test/cases/dirty_test.rb +163 -0
- data/test/cases/finder_respond_to_test.rb +76 -0
- data/test/{finder_test.rb → cases/finder_test.rb} +266 -33
- data/test/{fixtures_test.rb → cases/fixtures_test.rb} +88 -72
- data/test/cases/helper.rb +47 -0
- data/test/{inheritance_test.rb → cases/inheritance_test.rb} +61 -17
- data/test/cases/invalid_date_test.rb +24 -0
- data/test/{json_serialization_test.rb → cases/json_serialization_test.rb} +36 -11
- data/test/{lifecycle_test.rb → cases/lifecycle_test.rb} +16 -13
- data/test/{locking_test.rb → cases/locking_test.rb} +17 -10
- data/test/{method_scoping_test.rb → cases/method_scoping_test.rb} +75 -39
- data/test/{migration_test.rb → cases/migration_test.rb} +420 -80
- data/test/{migration_test_firebird.rb → cases/migration_test_firebird.rb} +3 -3
- data/test/{mixin_test.rb → cases/mixin_test.rb} +7 -6
- data/test/{modules_test.rb → cases/modules_test.rb} +11 -6
- data/test/{multiple_db_test.rb → cases/multiple_db_test.rb} +5 -5
- data/test/cases/named_scope_test.rb +157 -0
- data/test/{pk_test.rb → cases/pk_test.rb} +10 -10
- data/test/{query_cache_test.rb → cases/query_cache_test.rb} +12 -10
- data/test/{readonly_test.rb → cases/readonly_test.rb} +11 -11
- data/test/{reflection_test.rb → cases/reflection_test.rb} +15 -14
- data/test/{reserved_word_test_mysql.rb → cases/reserved_word_test_mysql.rb} +4 -5
- data/test/{schema_authorization_test_postgresql.rb → cases/schema_authorization_test_postgresql.rb} +5 -5
- data/test/cases/schema_dumper_test.rb +138 -0
- data/test/cases/schema_test_postgresql.rb +102 -0
- data/test/{serialization_test.rb → cases/serialization_test.rb} +7 -7
- data/test/{synonym_test_oracle.rb → cases/synonym_test_oracle.rb} +5 -5
- data/test/{table_name_test_sqlserver.rb → cases/table_name_test_sqlserver.rb} +3 -3
- data/test/{threaded_connections_test.rb → cases/threaded_connections_test.rb} +7 -7
- data/test/{transactions_test.rb → cases/transactions_test.rb} +31 -5
- data/test/{unconnected_test.rb → cases/unconnected_test.rb} +2 -2
- data/test/{validations_test.rb → cases/validations_test.rb} +141 -39
- data/test/{xml_serialization_test.rb → cases/xml_serialization_test.rb} +12 -12
- data/test/config.rb +5 -0
- data/test/connections/native_db2/connection.rb +1 -1
- data/test/connections/native_firebird/connection.rb +1 -1
- data/test/connections/native_frontbase/connection.rb +1 -1
- data/test/connections/native_mysql/connection.rb +1 -1
- data/test/connections/native_openbase/connection.rb +1 -1
- data/test/connections/native_oracle/connection.rb +1 -1
- data/test/connections/native_postgresql/connection.rb +1 -3
- data/test/connections/native_sqlite/connection.rb +2 -2
- data/test/connections/native_sqlite3/connection.rb +2 -2
- data/test/connections/native_sqlite3/in_memory_connection.rb +3 -3
- data/test/connections/native_sybase/connection.rb +1 -1
- data/test/fixtures/author_addresses.yml +5 -0
- data/test/fixtures/authors.yml +2 -0
- data/test/fixtures/clubs.yml +6 -0
- data/test/fixtures/jobs.yml +7 -0
- data/test/fixtures/members.yml +4 -0
- data/test/fixtures/memberships.yml +20 -0
- data/test/fixtures/owners.yml +7 -0
- data/test/fixtures/people.yml +4 -1
- data/test/fixtures/pets.yml +14 -0
- data/test/fixtures/posts.yml +1 -0
- data/test/fixtures/price_estimates.yml +7 -0
- data/test/fixtures/readers.yml +5 -0
- data/test/fixtures/references.yml +17 -0
- data/test/fixtures/sponsors.yml +9 -0
- data/test/fixtures/subscribers.yml +7 -0
- data/test/fixtures/subscriptions.yml +12 -0
- data/test/fixtures/taggings.yml +4 -1
- data/test/fixtures/topics.yml +22 -2
- data/test/fixtures/warehouse-things.yml +3 -0
- data/test/{fixtures/migrations_with_decimal → migrations/decimal}/1_give_me_big_numbers.rb +0 -0
- data/test/{fixtures/migrations_with_duplicate → migrations/duplicate}/1_people_have_last_names.rb +1 -1
- data/test/{fixtures/migrations_with_duplicate → migrations/duplicate}/2_we_need_reminders.rb +1 -1
- data/test/{fixtures/migrations_with_duplicate → migrations/duplicate}/3_foo.rb +0 -0
- data/test/{fixtures/migrations → migrations/duplicate}/3_innocent_jointable.rb +0 -0
- data/test/migrations/duplicate_names/20080507052938_chunky.rb +7 -0
- data/test/migrations/duplicate_names/20080507053028_chunky.rb +7 -0
- data/test/{fixtures/migrations_with_duplicate → migrations/interleaved/pass_1}/3_innocent_jointable.rb +0 -0
- data/test/{fixtures/migrations → migrations/interleaved/pass_2}/1_people_have_last_names.rb +1 -1
- data/test/{fixtures/migrations_with_missing_versions/4_innocent_jointable.rb → migrations/interleaved/pass_2/3_innocent_jointable.rb} +0 -0
- data/test/{fixtures/migrations_with_missing_versions → migrations/interleaved/pass_3}/1_people_have_last_names.rb +1 -1
- data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +8 -0
- data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +12 -0
- data/test/{fixtures/migrations_with_missing_versions → migrations/missing}/1000_people_have_middle_names.rb +1 -1
- data/test/migrations/missing/1_people_have_last_names.rb +9 -0
- data/test/{fixtures/migrations_with_missing_versions → migrations/missing}/3_we_need_reminders.rb +1 -1
- data/test/migrations/missing/4_innocent_jointable.rb +12 -0
- data/test/migrations/valid/1_people_have_last_names.rb +9 -0
- data/test/{fixtures/migrations → migrations/valid}/2_we_need_reminders.rb +1 -1
- data/test/migrations/valid/3_innocent_jointable.rb +12 -0
- data/test/{fixtures → models}/author.rb +28 -4
- data/test/{fixtures → models}/auto_id.rb +0 -0
- data/test/{fixtures → models}/binary.rb +0 -0
- data/test/{fixtures → models}/book.rb +0 -0
- data/test/{fixtures → models}/categorization.rb +0 -0
- data/test/{fixtures → models}/category.rb +8 -5
- data/test/{fixtures → models}/citation.rb +0 -0
- data/test/models/club.rb +7 -0
- data/test/{fixtures → models}/column_name.rb +0 -0
- data/test/{fixtures → models}/comment.rb +5 -3
- data/test/{fixtures → models}/company.rb +15 -6
- data/test/{fixtures → models}/company_in_module.rb +5 -3
- data/test/{fixtures → models}/computer.rb +0 -1
- data/test/{fixtures → models}/contact.rb +1 -1
- data/test/{fixtures → models}/course.rb +0 -0
- data/test/{fixtures → models}/customer.rb +8 -8
- data/test/{fixtures → models}/default.rb +0 -0
- data/test/{fixtures → models}/developer.rb +14 -10
- data/test/{fixtures → models}/edge.rb +0 -0
- data/test/{fixtures → models}/entrant.rb +0 -0
- data/test/models/guid.rb +2 -0
- data/test/{fixtures → models}/item.rb +0 -0
- data/test/models/job.rb +5 -0
- data/test/{fixtures → models}/joke.rb +0 -0
- data/test/{fixtures → models}/keyboard.rb +0 -0
- data/test/{fixtures → models}/legacy_thing.rb +0 -0
- data/test/{fixtures → models}/matey.rb +0 -0
- data/test/models/member.rb +9 -0
- data/test/models/membership.rb +9 -0
- data/test/{fixtures → models}/minimalistic.rb +0 -0
- data/test/{fixtures → models}/mixed_case_monkey.rb +0 -0
- data/test/{fixtures → models}/movie.rb +0 -0
- data/test/{fixtures → models}/order.rb +2 -2
- data/test/models/owner.rb +4 -0
- data/test/{fixtures → models}/parrot.rb +0 -0
- data/test/models/person.rb +10 -0
- data/test/models/pet.rb +4 -0
- data/test/models/pirate.rb +9 -0
- data/test/{fixtures → models}/post.rb +23 -2
- data/test/models/price_estimate.rb +3 -0
- data/test/{fixtures → models}/project.rb +1 -0
- data/test/{fixtures → models}/reader.rb +0 -0
- data/test/models/reference.rb +4 -0
- data/test/{fixtures → models}/reply.rb +7 -5
- data/test/{fixtures → models}/ship.rb +0 -0
- data/test/models/sponsor.rb +4 -0
- data/test/{fixtures → models}/subject.rb +0 -0
- data/test/{fixtures → models}/subscriber.rb +2 -0
- data/test/models/subscription.rb +4 -0
- data/test/{fixtures → models}/tag.rb +0 -0
- data/test/{fixtures → models}/tagging.rb +0 -0
- data/test/{fixtures → models}/task.rb +0 -0
- data/test/{fixtures → models}/topic.rb +32 -4
- data/test/{fixtures → models}/treasure.rb +2 -0
- data/test/{fixtures → models}/vertex.rb +0 -0
- data/test/models/warehouse_thing.rb +5 -0
- data/test/schema/mysql_specific_schema.rb +12 -0
- data/test/schema/postgresql_specific_schema.rb +103 -0
- data/test/schema/schema.rb +421 -0
- data/test/schema/schema2.rb +6 -0
- data/test/schema/sqlite_specific_schema.rb +25 -0
- data/test/schema/sqlserver_specific_schema.rb +5 -0
- metadata +192 -176
- data/test/aaa_create_tables_test.rb +0 -72
- data/test/abstract_unit.rb +0 -84
- data/test/active_schema_test_mysql.rb +0 -46
- data/test/all.sh +0 -8
- data/test/association_inheritance_reload.rb +0 -14
- data/test/associations_test.rb +0 -2177
- data/test/fixtures/bad_fixtures/attr_with_numeric_first_char +0 -1
- data/test/fixtures/bad_fixtures/attr_with_spaces +0 -1
- data/test/fixtures/bad_fixtures/blank_line +0 -3
- data/test/fixtures/bad_fixtures/duplicate_attributes +0 -3
- data/test/fixtures/bad_fixtures/missing_value +0 -1
- data/test/fixtures/db_definitions/db2.drop.sql +0 -33
- data/test/fixtures/db_definitions/db2.sql +0 -235
- data/test/fixtures/db_definitions/db22.drop.sql +0 -2
- data/test/fixtures/db_definitions/db22.sql +0 -5
- data/test/fixtures/db_definitions/firebird.drop.sql +0 -65
- data/test/fixtures/db_definitions/firebird.sql +0 -310
- data/test/fixtures/db_definitions/firebird2.drop.sql +0 -2
- data/test/fixtures/db_definitions/firebird2.sql +0 -6
- data/test/fixtures/db_definitions/frontbase.drop.sql +0 -33
- data/test/fixtures/db_definitions/frontbase.sql +0 -273
- data/test/fixtures/db_definitions/frontbase2.drop.sql +0 -1
- data/test/fixtures/db_definitions/frontbase2.sql +0 -4
- data/test/fixtures/db_definitions/openbase.drop.sql +0 -2
- data/test/fixtures/db_definitions/openbase.sql +0 -318
- data/test/fixtures/db_definitions/openbase2.drop.sql +0 -2
- data/test/fixtures/db_definitions/openbase2.sql +0 -7
- data/test/fixtures/db_definitions/oracle.drop.sql +0 -67
- data/test/fixtures/db_definitions/oracle.sql +0 -330
- data/test/fixtures/db_definitions/oracle2.drop.sql +0 -2
- data/test/fixtures/db_definitions/oracle2.sql +0 -6
- data/test/fixtures/db_definitions/postgresql.drop.sql +0 -44
- data/test/fixtures/db_definitions/postgresql.sql +0 -292
- data/test/fixtures/db_definitions/postgresql2.drop.sql +0 -2
- data/test/fixtures/db_definitions/postgresql2.sql +0 -4
- data/test/fixtures/db_definitions/schema.rb +0 -354
- data/test/fixtures/db_definitions/schema2.rb +0 -11
- data/test/fixtures/db_definitions/sqlite.drop.sql +0 -33
- data/test/fixtures/db_definitions/sqlite.sql +0 -219
- data/test/fixtures/db_definitions/sqlite2.drop.sql +0 -2
- data/test/fixtures/db_definitions/sqlite2.sql +0 -5
- data/test/fixtures/db_definitions/sybase.drop.sql +0 -35
- data/test/fixtures/db_definitions/sybase.sql +0 -222
- data/test/fixtures/db_definitions/sybase2.drop.sql +0 -4
- data/test/fixtures/db_definitions/sybase2.sql +0 -5
- data/test/fixtures/developers_projects/david_action_controller +0 -3
- data/test/fixtures/developers_projects/david_active_record +0 -3
- data/test/fixtures/developers_projects/jamis_active_record +0 -2
- data/test/fixtures/person.rb +0 -4
- data/test/fixtures/pirate.rb +0 -5
- data/test/fixtures/subscribers/first +0 -2
- data/test/fixtures/subscribers/second +0 -2
- data/test/schema_dumper_test.rb +0 -131
- data/test/schema_test_postgresql.rb +0 -64
@@ -19,7 +19,7 @@ module ActiveRecord
|
|
19
19
|
# # Same as above, just using explicit class references
|
20
20
|
# ActiveRecord::Base.observers = Cacher, GarbageCollector
|
21
21
|
#
|
22
|
-
# Note: Setting this does not instantiate the observers yet.
|
22
|
+
# Note: Setting this does not instantiate the observers yet. +instantiate_observers+ is
|
23
23
|
# called during startup, and before each development request.
|
24
24
|
def observers=(*observers)
|
25
25
|
@observers = observers.flatten
|
@@ -30,7 +30,7 @@ module ActiveRecord
|
|
30
30
|
@observers ||= []
|
31
31
|
end
|
32
32
|
|
33
|
-
# Instantiate the global
|
33
|
+
# Instantiate the global Active Record observers.
|
34
34
|
def instantiate_observers
|
35
35
|
return if @observers.blank?
|
36
36
|
@observers.each do |observer|
|
@@ -125,6 +125,20 @@ module ActiveRecord
|
|
125
125
|
#
|
126
126
|
# Observers will not be invoked unless you define these in your application configuration.
|
127
127
|
#
|
128
|
+
# == Loading
|
129
|
+
#
|
130
|
+
# Observers register themselves in the model class they observe, since it is the class that
|
131
|
+
# notifies them of events when they occur. As a side-effect, when an observer is loaded its
|
132
|
+
# corresponding model class is loaded.
|
133
|
+
#
|
134
|
+
# Up to (and including) Rails 2.0.2 observers were instantiated between plugins and
|
135
|
+
# application initializers. Now observers are loaded after application initializers,
|
136
|
+
# so observed models can make use of extensions.
|
137
|
+
#
|
138
|
+
# If by any chance you are using observed models in the initialization you can still
|
139
|
+
# load their observers by calling <tt>ModelObserver.instance</tt> before. Observers are
|
140
|
+
# singletons and that call instantiates and registers them.
|
141
|
+
#
|
128
142
|
class Observer
|
129
143
|
include Singleton
|
130
144
|
|
@@ -137,10 +151,10 @@ module ActiveRecord
|
|
137
151
|
end
|
138
152
|
|
139
153
|
# The class observed by default is inferred from the observer's class name:
|
140
|
-
# assert_equal
|
154
|
+
# assert_equal Person, PersonObserver.observed_class
|
141
155
|
def observed_class
|
142
|
-
if observed_class_name = name
|
143
|
-
observed_class_name
|
156
|
+
if observed_class_name = name[/(.*)Observer/, 1]
|
157
|
+
observed_class_name.constantize
|
144
158
|
else
|
145
159
|
nil
|
146
160
|
end
|
@@ -45,7 +45,7 @@ module ActiveRecord
|
|
45
45
|
end
|
46
46
|
|
47
47
|
# Returns an array of AssociationReflection objects for all the associations in the class. If you only want to reflect on a
|
48
|
-
# certain association type, pass in the symbol (
|
48
|
+
# certain association type, pass in the symbol (<tt>:has_many</tt>, <tt>:has_one</tt>, <tt>:belongs_to</tt>) for that as the first parameter.
|
49
49
|
# Example:
|
50
50
|
#
|
51
51
|
# Account.reflect_on_all_associations # returns an array of all associations
|
@@ -76,34 +76,38 @@ module ActiveRecord
|
|
76
76
|
@macro, @name, @options, @active_record = macro, name, options, active_record
|
77
77
|
end
|
78
78
|
|
79
|
-
# Returns the name of the macro,
|
80
|
-
#
|
79
|
+
# Returns the name of the macro. For example, <tt>composed_of :balance, :class_name => 'Money'</tt> will return
|
80
|
+
# <tt>:balance</tt> or for <tt>has_many :clients</tt> it will return <tt>:clients</tt>.
|
81
81
|
def name
|
82
82
|
@name
|
83
83
|
end
|
84
84
|
|
85
|
-
# Returns the type
|
86
|
-
#
|
85
|
+
# Returns the macro type. For example, <tt>composed_of :balance, :class_name => 'Money'</tt> will return <tt>:composed_of</tt>
|
86
|
+
# or for <tt>has_many :clients</tt> will return <tt>:has_many</tt>.
|
87
87
|
def macro
|
88
88
|
@macro
|
89
89
|
end
|
90
90
|
|
91
|
-
# Returns the hash of options used for the macro,
|
92
|
-
#
|
91
|
+
# Returns the hash of options used for the macro. For example, it would return <tt>{ :class_name => "Money" }</tt> for
|
92
|
+
# <tt>composed_of :balance, :class_name => 'Money'</tt> or +{}+ for <tt>has_many :clients</tt>.
|
93
93
|
def options
|
94
94
|
@options
|
95
95
|
end
|
96
96
|
|
97
|
-
# Returns the class for the macro,
|
98
|
-
#
|
97
|
+
# Returns the class for the macro. For example, <tt>composed_of :balance, :class_name => 'Money'</tt> returns the Money
|
98
|
+
# class and <tt>has_many :clients</tt> returns the Client class.
|
99
99
|
def klass
|
100
100
|
@klass ||= class_name.constantize
|
101
101
|
end
|
102
102
|
|
103
|
+
# Returns the class name for the macro. For example, <tt>composed_of :balance, :class_name => 'Money'</tt> returns <tt>'Money'</tt>
|
104
|
+
# and <tt>has_many :clients</tt> returns <tt>'Client'</tt>.
|
103
105
|
def class_name
|
104
106
|
@class_name ||= options[:class_name] || derive_class_name
|
105
107
|
end
|
106
108
|
|
109
|
+
# Returns +true+ if +self+ and +other_aggregation+ have the same +name+ attribute, +active_record+ attribute,
|
110
|
+
# and +other_aggregation+ has an options hash assigned to it.
|
107
111
|
def ==(other_aggregation)
|
108
112
|
name == other_aggregation.name && other_aggregation.options && active_record == other_aggregation.active_record
|
109
113
|
end
|
@@ -129,6 +133,10 @@ module ActiveRecord
|
|
129
133
|
@table_name ||= klass.table_name
|
130
134
|
end
|
131
135
|
|
136
|
+
def quoted_table_name
|
137
|
+
@quoted_table_name ||= klass.quoted_table_name
|
138
|
+
end
|
139
|
+
|
132
140
|
def primary_key_name
|
133
141
|
@primary_key_name ||= options[:foreign_key] || derive_primary_key_name
|
134
142
|
end
|
@@ -145,22 +153,34 @@ module ActiveRecord
|
|
145
153
|
end
|
146
154
|
end
|
147
155
|
|
156
|
+
# Returns the AssociationReflection object specified in the <tt>:through</tt> option
|
157
|
+
# of a HasManyThrough or HasOneThrough association. Example:
|
158
|
+
#
|
159
|
+
# class Post < ActiveRecord::Base
|
160
|
+
# has_many :taggings
|
161
|
+
# has_many :tags, :through => :taggings
|
162
|
+
# end
|
163
|
+
#
|
164
|
+
# tags_reflection = Post.reflect_on_association(:tags)
|
165
|
+
# taggings_reflection = tags_reflection.through_reflection
|
166
|
+
#
|
148
167
|
def through_reflection
|
149
168
|
@through_reflection ||= options[:through] ? active_record.reflect_on_association(options[:through]) : false
|
150
169
|
end
|
151
170
|
|
152
|
-
# Gets an array of possible
|
171
|
+
# Gets an array of possible <tt>:through</tt> source reflection names:
|
153
172
|
#
|
154
|
-
# [singularized, pluralized]
|
173
|
+
# [:singularized, :pluralized]
|
155
174
|
#
|
156
175
|
def source_reflection_names
|
157
176
|
@source_reflection_names ||= (options[:source] ? [options[:source]] : [name.to_s.singularize, name]).collect { |n| n.to_sym }
|
158
177
|
end
|
159
178
|
|
160
|
-
# Gets the source of the through reflection. It checks both a singularized and pluralized form for
|
161
|
-
# (The
|
179
|
+
# Gets the source of the through reflection. It checks both a singularized and pluralized form for <tt>:belongs_to</tt> or <tt>:has_many</tt>.
|
180
|
+
# (The <tt>:tags</tt> association on Tagging below.)
|
162
181
|
#
|
163
|
-
# class Post
|
182
|
+
# class Post < ActiveRecord::Base
|
183
|
+
# has_many :taggings
|
164
184
|
# has_many :tags, :through => :taggings
|
165
185
|
# end
|
166
186
|
#
|
data/lib/active_record/schema.rb
CHANGED
@@ -30,28 +30,21 @@ module ActiveRecord
|
|
30
30
|
|
31
31
|
# Eval the given block. All methods available to the current connection
|
32
32
|
# adapter are available within the block, so you can easily use the
|
33
|
-
# database definition DSL to build up your schema (
|
34
|
-
#
|
33
|
+
# database definition DSL to build up your schema (+create_table+,
|
34
|
+
# +add_index+, etc.).
|
35
35
|
#
|
36
36
|
# The +info+ hash is optional, and if given is used to define metadata
|
37
|
-
# about the current schema (
|
37
|
+
# about the current schema (currently, only the schema's version):
|
38
38
|
#
|
39
|
-
# ActiveRecord::Schema.define(:version =>
|
39
|
+
# ActiveRecord::Schema.define(:version => 20380119000001) do
|
40
40
|
# ...
|
41
41
|
# end
|
42
42
|
def self.define(info={}, &block)
|
43
43
|
instance_eval(&block)
|
44
44
|
|
45
|
-
unless info.
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
info = info.map do |k,v|
|
50
|
-
v = Base.connection.quote(v, cols.detect { |c| c.name == k.to_s })
|
51
|
-
"#{k} = #{v}"
|
52
|
-
end
|
53
|
-
|
54
|
-
Base.connection.update "UPDATE #{Migrator.schema_info_table_name} SET #{info.join(", ")}"
|
45
|
+
unless info[:version].blank?
|
46
|
+
initialize_schema_migrations_table
|
47
|
+
assume_migrated_upto_version info[:version]
|
55
48
|
end
|
56
49
|
end
|
57
50
|
end
|
@@ -30,15 +30,15 @@ module ActiveRecord
|
|
30
30
|
def initialize(connection)
|
31
31
|
@connection = connection
|
32
32
|
@types = @connection.native_database_types
|
33
|
-
@
|
33
|
+
@version = Migrator::current_version rescue nil
|
34
34
|
end
|
35
35
|
|
36
36
|
def header(stream)
|
37
|
-
define_params = @
|
37
|
+
define_params = @version ? ":version => #{@version}" : ""
|
38
38
|
|
39
39
|
stream.puts <<HEADER
|
40
40
|
# This file is auto-generated from the current state of the database. Instead of editing this file,
|
41
|
-
# please use the migrations feature of
|
41
|
+
# please use the migrations feature of Active Record to incrementally modify your database, and
|
42
42
|
# then regenerate this schema definition.
|
43
43
|
#
|
44
44
|
# Note that this schema.rb definition is the authoritative source for your database schema. If you need
|
@@ -59,7 +59,7 @@ HEADER
|
|
59
59
|
|
60
60
|
def tables(stream)
|
61
61
|
@connection.tables.sort.each do |tbl|
|
62
|
-
next if [
|
62
|
+
next if ['schema_migrations', ignore_tables].flatten.any? do |ignored|
|
63
63
|
case ignored
|
64
64
|
when String; tbl == ignored
|
65
65
|
when Regexp; tbl =~ ignored
|
@@ -8,11 +8,11 @@ module ActiveRecord #:nodoc:
|
|
8
8
|
end
|
9
9
|
|
10
10
|
# To replicate the behavior in ActiveRecord#attributes,
|
11
|
-
#
|
11
|
+
# <tt>:except</tt> takes precedence over <tt>:only</tt>. If <tt>:only</tt> is not set
|
12
12
|
# for a N level model but is set for the N+1 level models,
|
13
|
-
# then because
|
14
|
-
# level model can have both
|
15
|
-
#
|
13
|
+
# then because <tt>:except</tt> is set to a default value, the second
|
14
|
+
# level model can have both <tt>:except</tt> and <tt>:only</tt> set. So if
|
15
|
+
# <tt>:only</tt> is set, always delete <tt>:except</tt>.
|
16
16
|
def serializable_attribute_names
|
17
17
|
attribute_names = @record.attribute_names
|
18
18
|
|
@@ -38,7 +38,7 @@ module ActiveRecord #:nodoc:
|
|
38
38
|
serializable_attribute_names + serializable_method_names
|
39
39
|
end
|
40
40
|
|
41
|
-
# Add associations specified via the
|
41
|
+
# Add associations specified via the <tt>:includes</tt> option.
|
42
42
|
# Expects a block that takes as arguments:
|
43
43
|
# +association+ - name of the association
|
44
44
|
# +records+ - the association record(s) to be serialized
|
@@ -1,5 +1,10 @@
|
|
1
1
|
module ActiveRecord #:nodoc:
|
2
2
|
module Serialization
|
3
|
+
def self.included(base)
|
4
|
+
base.cattr_accessor :include_root_in_json, :instance_writer => false
|
5
|
+
base.extend ClassMethods
|
6
|
+
end
|
7
|
+
|
3
8
|
# Returns a JSON string representing the model. Some configuration is
|
4
9
|
# available through +options+.
|
5
10
|
#
|
@@ -8,37 +13,32 @@ module ActiveRecord #:nodoc:
|
|
8
13
|
#
|
9
14
|
# konata = User.find(1)
|
10
15
|
# konata.to_json
|
16
|
+
# # => {"id": 1, "name": "Konata Izumi", "age": 16,
|
17
|
+
# "created_at": "2006/08/01", "awesome": true}
|
11
18
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
# The :only and :except options can be used to limit the attributes
|
16
|
-
# included, and work similar to the #attributes method. For example:
|
19
|
+
# The <tt>:only</tt> and <tt>:except</tt> options can be used to limit the attributes
|
20
|
+
# included, and work similar to the +attributes+ method. For example:
|
17
21
|
#
|
18
22
|
# konata.to_json(:only => [ :id, :name ])
|
19
|
-
#
|
20
|
-
# {"id": 1, "name": "Konata Izumi"}
|
23
|
+
# # => {"id": 1, "name": "Konata Izumi"}
|
21
24
|
#
|
22
25
|
# konata.to_json(:except => [ :id, :created_at, :age ])
|
26
|
+
# # => {"name": "Konata Izumi", "awesome": true}
|
23
27
|
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# To include any methods on the model, use :methods.
|
28
|
+
# To include any methods on the model, use <tt>:methods</tt>.
|
27
29
|
#
|
28
30
|
# konata.to_json(:methods => :permalink)
|
31
|
+
# # => {"id": 1, "name": "Konata Izumi", "age": 16,
|
32
|
+
# "created_at": "2006/08/01", "awesome": true,
|
33
|
+
# "permalink": "1-konata-izumi"}
|
29
34
|
#
|
30
|
-
#
|
31
|
-
# "created_at": "2006/08/01", "awesome": true,
|
32
|
-
# "permalink": "1-konata-izumi"}
|
33
|
-
#
|
34
|
-
# To include associations, use :include.
|
35
|
+
# To include associations, use <tt>:include</tt>.
|
35
36
|
#
|
36
37
|
# konata.to_json(:include => :posts)
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
# {"id": 2, author_id: 1, "title": "So I was thinking"}]}
|
38
|
+
# # => {"id": 1, "name": "Konata Izumi", "age": 16,
|
39
|
+
# "created_at": "2006/08/01", "awesome": true,
|
40
|
+
# "posts": [{"id": 1, "author_id": 1, "title": "Welcome to the weblog"},
|
41
|
+
# {"id": 2, author_id: 1, "title": "So I was thinking"}]}
|
42
42
|
#
|
43
43
|
# 2nd level and higher order associations work as well:
|
44
44
|
#
|
@@ -46,15 +46,18 @@ module ActiveRecord #:nodoc:
|
|
46
46
|
# :include => { :comments => {
|
47
47
|
# :only => :body } },
|
48
48
|
# :only => :title } })
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
54
|
-
#
|
55
|
-
# "title": "So I was thinking"}]}
|
49
|
+
# # => {"id": 1, "name": "Konata Izumi", "age": 16,
|
50
|
+
# "created_at": "2006/08/01", "awesome": true,
|
51
|
+
# "posts": [{"comments": [{"body": "1st post!"}, {"body": "Second!"}],
|
52
|
+
# "title": "Welcome to the weblog"},
|
53
|
+
# {"comments": [{"body": "Don't think too hard"}],
|
54
|
+
# "title": "So I was thinking"}]}
|
56
55
|
def to_json(options = {})
|
57
|
-
|
56
|
+
if include_root_in_json
|
57
|
+
"{#{self.class.json_class_name}: #{JsonSerializer.new(self, options).to_s}}"
|
58
|
+
else
|
59
|
+
JsonSerializer.new(self, options).to_s
|
60
|
+
end
|
58
61
|
end
|
59
62
|
|
60
63
|
def from_json(json)
|
@@ -67,5 +70,11 @@ module ActiveRecord #:nodoc:
|
|
67
70
|
serializable_record.to_json
|
68
71
|
end
|
69
72
|
end
|
73
|
+
|
74
|
+
module ClassMethods
|
75
|
+
def json_class_name
|
76
|
+
@json_class_name ||= name.demodulize.underscore.inspect
|
77
|
+
end
|
78
|
+
end
|
70
79
|
end
|
71
80
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module ActiveRecord #:nodoc:
|
2
2
|
module Serialization
|
3
|
-
# Builds an XML document to represent the model.
|
4
|
-
# available through +options
|
5
|
-
# override ActiveRecord
|
3
|
+
# Builds an XML document to represent the model. Some configuration is
|
4
|
+
# available through +options+. However more complicated cases should
|
5
|
+
# override ActiveRecord::Base#to_xml.
|
6
6
|
#
|
7
7
|
# By default the generated XML document will include the processing
|
8
|
-
# instruction and all object's attributes.
|
8
|
+
# instruction and all the object's attributes. For example:
|
9
9
|
#
|
10
10
|
# <?xml version="1.0" encoding="UTF-8"?>
|
11
11
|
# <topic>
|
@@ -22,12 +22,12 @@ module ActiveRecord #:nodoc:
|
|
22
22
|
# <last-read type="date">2004-04-15</last-read>
|
23
23
|
# </topic>
|
24
24
|
#
|
25
|
-
# This behavior can be controlled with
|
26
|
-
#
|
27
|
-
#
|
28
|
-
# The default is to dasherize all column names,
|
29
|
-
#
|
30
|
-
# in the XML output
|
25
|
+
# This behavior can be controlled with <tt>:only</tt>, <tt>:except</tt>,
|
26
|
+
# <tt>:skip_instruct</tt>, <tt>:skip_types</tt> and <tt>:dasherize</tt>.
|
27
|
+
# The <tt>:only</tt> and <tt>:except</tt> options are the same as for the
|
28
|
+
# +attributes+ method. The default is to dasherize all column names, but you
|
29
|
+
# can disable this setting <tt>:dasherize</tt> to +false+. To not have the
|
30
|
+
# column type included in the XML output set <tt>:skip_types</tt> to +true+.
|
31
31
|
#
|
32
32
|
# For instance:
|
33
33
|
#
|
@@ -43,7 +43,7 @@ module ActiveRecord #:nodoc:
|
|
43
43
|
# <last-read type="date">2004-04-15</last-read>
|
44
44
|
# </topic>
|
45
45
|
#
|
46
|
-
# To include first level associations use
|
46
|
+
# To include first level associations use <tt>:include</tt>:
|
47
47
|
#
|
48
48
|
# firm.to_xml :include => [ :account, :clients ]
|
49
49
|
#
|
@@ -68,7 +68,37 @@ module ActiveRecord #:nodoc:
|
|
68
68
|
# </account>
|
69
69
|
# </firm>
|
70
70
|
#
|
71
|
-
# To include
|
71
|
+
# To include deeper levels of associations pass a hash like this:
|
72
|
+
#
|
73
|
+
# firm.to_xml :include => {:account => {}, :clients => {:include => :address}}
|
74
|
+
# <?xml version="1.0" encoding="UTF-8"?>
|
75
|
+
# <firm>
|
76
|
+
# <id type="integer">1</id>
|
77
|
+
# <rating type="integer">1</rating>
|
78
|
+
# <name>37signals</name>
|
79
|
+
# <clients type="array">
|
80
|
+
# <client>
|
81
|
+
# <rating type="integer">1</rating>
|
82
|
+
# <name>Summit</name>
|
83
|
+
# <address>
|
84
|
+
# ...
|
85
|
+
# </address>
|
86
|
+
# </client>
|
87
|
+
# <client>
|
88
|
+
# <rating type="integer">1</rating>
|
89
|
+
# <name>Microsoft</name>
|
90
|
+
# <address>
|
91
|
+
# ...
|
92
|
+
# </address>
|
93
|
+
# </client>
|
94
|
+
# </clients>
|
95
|
+
# <account>
|
96
|
+
# <id type="integer">1</id>
|
97
|
+
# <credit-limit type="integer">50</credit-limit>
|
98
|
+
# </account>
|
99
|
+
# </firm>
|
100
|
+
#
|
101
|
+
# To include any methods on the model being called use <tt>:methods</tt>:
|
72
102
|
#
|
73
103
|
# firm.to_xml :methods => [ :calculated_earnings, :real_earnings ]
|
74
104
|
#
|
@@ -78,9 +108,8 @@ module ActiveRecord #:nodoc:
|
|
78
108
|
# <real-earnings>5</real-earnings>
|
79
109
|
# </firm>
|
80
110
|
#
|
81
|
-
# To call any
|
82
|
-
#
|
83
|
-
# given to #to_xml.
|
111
|
+
# To call any additional Procs use <tt>:procs</tt>. The Procs are passed a
|
112
|
+
# modified version of the options hash that was given to +to_xml+:
|
84
113
|
#
|
85
114
|
# proc = Proc.new { |options| options[:builder].tag!('abc', 'def') }
|
86
115
|
# firm.to_xml :procs => [ proc ]
|
@@ -90,7 +119,7 @@ module ActiveRecord #:nodoc:
|
|
90
119
|
# <abc>def</abc>
|
91
120
|
# </firm>
|
92
121
|
#
|
93
|
-
# Alternatively, you can
|
122
|
+
# Alternatively, you can yield the builder object as part of the +to_xml+ call:
|
94
123
|
#
|
95
124
|
# firm.to_xml do |xml|
|
96
125
|
# xml.creator do
|
@@ -107,8 +136,9 @@ module ActiveRecord #:nodoc:
|
|
107
136
|
# </creator>
|
108
137
|
# </firm>
|
109
138
|
#
|
110
|
-
#
|
111
|
-
# subclasses
|
139
|
+
# As noted above, you may override +to_xml+ in your ActiveRecord::Base
|
140
|
+
# subclasses to have complete control about what's generated. The general
|
141
|
+
# form of doing this is:
|
112
142
|
#
|
113
143
|
# class IHaveMyOwnXML < ActiveRecord::Base
|
114
144
|
# def to_xml(options = {})
|
@@ -155,13 +185,6 @@ module ActiveRecord #:nodoc:
|
|
155
185
|
!options.has_key?(:dasherize) || options[:dasherize]
|
156
186
|
end
|
157
187
|
|
158
|
-
|
159
|
-
# To replicate the behavior in ActiveRecord#attributes,
|
160
|
-
# :except takes precedence over :only. If :only is not set
|
161
|
-
# for a N level model but is set for the N+1 level models,
|
162
|
-
# then because :except is set to a default value, the second
|
163
|
-
# level model can have both :except and :only set. So if
|
164
|
-
# :only is set, always delete :except.
|
165
188
|
def serializable_attributes
|
166
189
|
serializable_attribute_names.collect { |name| Attribute.new(name, @record) }
|
167
190
|
end
|
@@ -250,14 +273,14 @@ module ActiveRecord #:nodoc:
|
|
250
273
|
end
|
251
274
|
|
252
275
|
# There is a significant speed improvement if the value
|
253
|
-
# does not need to be escaped, as
|
254
|
-
# to ensure that valid XML is generated.
|
276
|
+
# does not need to be escaped, as <tt>tag!</tt> escapes all values
|
277
|
+
# to ensure that valid XML is generated. For known binary
|
255
278
|
# values, it is at least an order of magnitude faster to
|
256
279
|
# Base64 encode binary values and directly put them in the
|
257
280
|
# output XML than to pass the original value or the Base64
|
258
|
-
# encoded value to the
|
281
|
+
# encoded value to the <tt>tag!</tt> method. It definitely makes
|
259
282
|
# no sense to Base64 encode the value and then give it to
|
260
|
-
#
|
283
|
+
# <tt>tag!</tt>, since that just adds additional overhead.
|
261
284
|
def needs_encoding?
|
262
285
|
![ :binary, :date, :datetime, :boolean, :float, :integer ].include?(type)
|
263
286
|
end
|