activerecord 1.15.6 → 2.0.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 +2454 -34
- data/README +1 -1
- data/RUNNING_UNIT_TESTS +3 -34
- data/Rakefile +98 -77
- data/install.rb +1 -1
- data/lib/active_record.rb +13 -22
- data/lib/active_record/aggregations.rb +38 -49
- data/lib/active_record/associations.rb +452 -333
- data/lib/active_record/associations/association_collection.rb +66 -20
- data/lib/active_record/associations/association_proxy.rb +9 -8
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +46 -51
- data/lib/active_record/associations/has_many_association.rb +21 -57
- data/lib/active_record/associations/has_many_through_association.rb +38 -18
- data/lib/active_record/associations/has_one_association.rb +30 -14
- data/lib/active_record/attribute_methods.rb +253 -0
- data/lib/active_record/base.rb +719 -494
- data/lib/active_record/calculations.rb +62 -63
- data/lib/active_record/callbacks.rb +57 -83
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +38 -9
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +56 -15
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +87 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +23 -12
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +191 -62
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +37 -34
- data/lib/active_record/connection_adapters/abstract_adapter.rb +28 -17
- data/lib/active_record/connection_adapters/mysql_adapter.rb +119 -37
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +473 -210
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +34 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +91 -107
- data/lib/active_record/fixtures.rb +503 -113
- data/lib/active_record/locking/optimistic.rb +72 -34
- data/lib/active_record/migration.rb +80 -57
- data/lib/active_record/observer.rb +13 -10
- data/lib/active_record/query_cache.rb +16 -57
- data/lib/active_record/reflection.rb +35 -38
- data/lib/active_record/schema.rb +5 -5
- data/lib/active_record/schema_dumper.rb +35 -13
- data/lib/active_record/serialization.rb +98 -0
- data/lib/active_record/serializers/json_serializer.rb +71 -0
- data/lib/active_record/{xml_serialization.rb → serializers/xml_serializer.rb} +90 -83
- data/lib/active_record/timestamp.rb +20 -21
- data/lib/active_record/transactions.rb +39 -43
- data/lib/active_record/validations.rb +256 -107
- data/lib/active_record/version.rb +3 -3
- data/lib/activerecord.rb +1 -0
- data/test/aaa_create_tables_test.rb +15 -2
- data/test/abstract_unit.rb +24 -17
- data/test/active_schema_test_mysql.rb +20 -8
- data/test/adapter_test.rb +23 -5
- data/test/adapter_test_sqlserver.rb +15 -1
- data/test/aggregations_test.rb +16 -1
- data/test/all.sh +2 -2
- data/test/associations/ar_joins_test.rb +0 -0
- data/test/associations/callbacks_test.rb +51 -30
- data/test/associations/cascaded_eager_loading_test.rb +1 -29
- data/test/associations/eager_singularization_test.rb +145 -0
- data/test/associations/eager_test.rb +42 -6
- data/test/associations/extension_test.rb +6 -1
- data/test/associations/inner_join_association_test.rb +88 -0
- data/test/associations/join_model_test.rb +47 -16
- data/test/associations_test.rb +449 -226
- data/test/attribute_methods_test.rb +97 -0
- data/test/base_test.rb +251 -105
- data/test/binary_test.rb +22 -27
- data/test/calculations_test.rb +37 -5
- data/test/callbacks_test.rb +23 -0
- data/test/connection_test_firebird.rb +2 -2
- data/test/connection_test_mysql.rb +30 -0
- data/test/connections/native_mysql/connection.rb +3 -0
- data/test/connections/native_sqlite/connection.rb +5 -14
- data/test/connections/native_sqlite3/connection.rb +5 -14
- data/test/connections/native_sqlite3/in_memory_connection.rb +1 -1
- data/test/{copy_table_sqlite.rb → copy_table_test_sqlite.rb} +8 -3
- data/test/datatype_test_postgresql.rb +178 -27
- data/test/{empty_date_time_test.rb → date_time_test.rb} +13 -1
- data/test/defaults_test.rb +8 -1
- data/test/deprecated_finder_test.rb +7 -128
- data/test/finder_test.rb +192 -54
- data/test/fixtures/all/developers.yml +0 -0
- data/test/fixtures/all/people.csv +0 -0
- data/test/fixtures/all/tasks.yml +0 -0
- data/test/fixtures/author.rb +12 -5
- data/test/fixtures/binaries.yml +130 -435
- data/test/fixtures/category.rb +6 -0
- data/test/fixtures/company.rb +8 -1
- data/test/fixtures/computer.rb +1 -0
- data/test/fixtures/contact.rb +16 -0
- data/test/fixtures/customer.rb +2 -2
- data/test/fixtures/db_definitions/db2.drop.sql +1 -0
- data/test/fixtures/db_definitions/db2.sql +4 -0
- data/test/fixtures/db_definitions/firebird.drop.sql +3 -1
- data/test/fixtures/db_definitions/firebird.sql +6 -0
- data/test/fixtures/db_definitions/frontbase.drop.sql +1 -0
- data/test/fixtures/db_definitions/frontbase.sql +5 -0
- data/test/fixtures/db_definitions/openbase.sql +41 -25
- data/test/fixtures/db_definitions/oracle.drop.sql +2 -0
- data/test/fixtures/db_definitions/oracle.sql +5 -0
- data/test/fixtures/db_definitions/postgresql.drop.sql +7 -0
- data/test/fixtures/db_definitions/postgresql.sql +87 -58
- data/test/fixtures/db_definitions/postgresql2.sql +1 -2
- data/test/fixtures/db_definitions/schema.rb +280 -0
- data/test/fixtures/db_definitions/schema2.rb +11 -0
- data/test/fixtures/db_definitions/sqlite.drop.sql +1 -0
- data/test/fixtures/db_definitions/sqlite.sql +4 -0
- data/test/fixtures/db_definitions/sybase.drop.sql +1 -0
- data/test/fixtures/db_definitions/sybase.sql +4 -0
- data/test/fixtures/developer.rb +10 -0
- data/test/fixtures/example.log +1 -0
- data/test/fixtures/flowers.jpg +0 -0
- data/test/fixtures/item.rb +7 -0
- data/test/fixtures/items.yml +4 -0
- data/test/fixtures/joke.rb +0 -3
- data/test/fixtures/matey.rb +4 -0
- data/test/fixtures/mateys.yml +4 -0
- data/test/fixtures/minimalistic.rb +2 -0
- data/test/fixtures/minimalistics.yml +2 -0
- data/test/fixtures/mixins.yml +2 -100
- data/test/fixtures/parrot.rb +13 -0
- data/test/fixtures/parrots.yml +27 -0
- data/test/fixtures/parrots_pirates.yml +7 -0
- data/test/fixtures/pirate.rb +5 -0
- data/test/fixtures/pirates.yml +9 -0
- data/test/fixtures/post.rb +1 -0
- data/test/fixtures/project.rb +3 -2
- data/test/fixtures/reserved_words/distinct.yml +5 -0
- data/test/fixtures/reserved_words/distincts_selects.yml +11 -0
- data/test/fixtures/reserved_words/group.yml +14 -0
- data/test/fixtures/reserved_words/select.yml +8 -0
- data/test/fixtures/reserved_words/values.yml +7 -0
- data/test/fixtures/ship.rb +3 -0
- data/test/fixtures/ships.yml +5 -0
- data/test/fixtures/tagging.rb +4 -0
- data/test/fixtures/taggings.yml +8 -1
- data/test/fixtures/topic.rb +13 -1
- data/test/fixtures/treasure.rb +4 -0
- data/test/fixtures/treasures.yml +10 -0
- data/test/fixtures_test.rb +205 -24
- data/test/inheritance_test.rb +7 -1
- data/test/json_serialization_test.rb +180 -0
- data/test/lifecycle_test.rb +1 -1
- data/test/locking_test.rb +85 -2
- data/test/migration_test.rb +206 -40
- data/test/mixin_test.rb +13 -515
- data/test/pk_test.rb +3 -6
- data/test/query_cache_test.rb +104 -0
- data/test/reflection_test.rb +16 -0
- data/test/reserved_word_test_mysql.rb +177 -0
- data/test/schema_dumper_test.rb +38 -3
- data/test/serialization_test.rb +47 -0
- data/test/transactions_test.rb +74 -23
- data/test/unconnected_test.rb +1 -1
- data/test/validations_test.rb +322 -32
- data/test/xml_serialization_test.rb +121 -44
- metadata +48 -41
- data/examples/associations.rb +0 -87
- data/examples/shared_setup.rb +0 -15
- data/examples/validation.rb +0 -85
- data/lib/active_record/acts/list.rb +0 -256
- data/lib/active_record/acts/nested_set.rb +0 -211
- data/lib/active_record/acts/tree.rb +0 -96
- data/lib/active_record/connection_adapters/db2_adapter.rb +0 -228
- data/lib/active_record/connection_adapters/firebird_adapter.rb +0 -728
- data/lib/active_record/connection_adapters/frontbase_adapter.rb +0 -861
- data/lib/active_record/connection_adapters/openbase_adapter.rb +0 -350
- data/lib/active_record/connection_adapters/oracle_adapter.rb +0 -690
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +0 -591
- data/lib/active_record/connection_adapters/sybase_adapter.rb +0 -662
- data/lib/active_record/deprecated_associations.rb +0 -104
- data/lib/active_record/deprecated_finders.rb +0 -44
- data/lib/active_record/vendor/simple.rb +0 -693
- data/lib/active_record/wrappers/yaml_wrapper.rb +0 -15
- data/lib/active_record/wrappings.rb +0 -58
- data/test/connections/native_sqlserver/connection.rb +0 -23
- data/test/connections/native_sqlserver_odbc/connection.rb +0 -25
- data/test/deprecated_associations_test.rb +0 -396
- data/test/fixtures/db_definitions/mysql.drop.sql +0 -32
- data/test/fixtures/db_definitions/mysql.sql +0 -234
- data/test/fixtures/db_definitions/mysql2.drop.sql +0 -2
- data/test/fixtures/db_definitions/mysql2.sql +0 -5
- data/test/fixtures/db_definitions/sqlserver.drop.sql +0 -34
- data/test/fixtures/db_definitions/sqlserver.sql +0 -243
- data/test/fixtures/db_definitions/sqlserver2.drop.sql +0 -2
- data/test/fixtures/db_definitions/sqlserver2.sql +0 -5
- data/test/fixtures/mixin.rb +0 -63
- data/test/mixin_nested_set_test.rb +0 -196
@@ -84,10 +84,11 @@ module ActiveRecord
|
|
84
84
|
#
|
85
85
|
# Observers will by default be mapped to the class with which they share a name. So CommentObserver will
|
86
86
|
# be tied to observing Comment, ProductManagerObserver to ProductManager, and so on. If you want to name your observer
|
87
|
-
# differently than the class you're interested in observing, you can use the Observer.observe class method
|
87
|
+
# differently than the class you're interested in observing, you can use the Observer.observe class method which takes
|
88
|
+
# either the concrete class (Product) or a symbol for that class (:product):
|
88
89
|
#
|
89
90
|
# class AuditObserver < ActiveRecord::Observer
|
90
|
-
# observe
|
91
|
+
# observe :account
|
91
92
|
#
|
92
93
|
# def after_update(account)
|
93
94
|
# AuditTrail.new(account, "UPDATED")
|
@@ -97,7 +98,7 @@ module ActiveRecord
|
|
97
98
|
# If the audit observer needs to watch more than one kind of object, this can be specified with multiple arguments:
|
98
99
|
#
|
99
100
|
# class AuditObserver < ActiveRecord::Observer
|
100
|
-
# observe
|
101
|
+
# observe :account, :balance
|
101
102
|
#
|
102
103
|
# def after_update(record)
|
103
104
|
# AuditTrail.new(record, "UPDATED")
|
@@ -127,20 +128,22 @@ module ActiveRecord
|
|
127
128
|
class Observer
|
128
129
|
include Singleton
|
129
130
|
|
130
|
-
# Observer subclasses should be reloaded by the dispatcher in Rails
|
131
|
-
# when Dependencies.mechanism = :load.
|
132
|
-
include Reloadable::Deprecated
|
133
|
-
|
134
131
|
class << self
|
135
132
|
# Attaches the observer to the supplied model classes.
|
136
133
|
def observe(*models)
|
134
|
+
models.flatten!
|
135
|
+
models.collect! { |model| model.is_a?(Symbol) ? model.to_s.camelize.constantize : model }
|
137
136
|
define_method(:observed_classes) { Set.new(models) }
|
138
137
|
end
|
139
138
|
|
140
139
|
# The class observed by default is inferred from the observer's class name:
|
141
140
|
# assert_equal [Person], PersonObserver.observed_class
|
142
141
|
def observed_class
|
143
|
-
name.scan(/(.*)Observer/)[0]
|
142
|
+
if observed_class_name = name.scan(/(.*)Observer/)[0]
|
143
|
+
observed_class_name[0].constantize
|
144
|
+
else
|
145
|
+
nil
|
146
|
+
end
|
144
147
|
end
|
145
148
|
end
|
146
149
|
|
@@ -163,11 +166,11 @@ module ActiveRecord
|
|
163
166
|
|
164
167
|
protected
|
165
168
|
def observed_classes
|
166
|
-
Set.new([self.class.observed_class].flatten)
|
169
|
+
Set.new([self.class.observed_class].compact.flatten)
|
167
170
|
end
|
168
171
|
|
169
172
|
def observed_subclasses
|
170
|
-
observed_classes.
|
173
|
+
observed_classes.collect(&:subclasses).flatten
|
171
174
|
end
|
172
175
|
|
173
176
|
def add_observer!(klass)
|
@@ -1,64 +1,23 @@
|
|
1
1
|
module ActiveRecord
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
@query_cache = {}
|
10
|
-
end
|
11
|
-
|
12
|
-
def select_all(sql, name = nil)
|
13
|
-
(@query_cache[sql] ||= @connection.select_all(sql, name)).dup
|
14
|
-
end
|
15
|
-
|
16
|
-
def select_one(sql, name = nil)
|
17
|
-
@query_cache[sql] ||= @connection.select_one(sql, name)
|
18
|
-
end
|
19
|
-
|
20
|
-
def columns(table_name, name = nil)
|
21
|
-
@query_cache["SHOW FIELDS FROM #{table_name}"] ||= @connection.columns(table_name, name)
|
22
|
-
end
|
23
|
-
|
24
|
-
def insert(sql, name = nil, pk = nil, id_value = nil)
|
25
|
-
clear_query_cache
|
26
|
-
@connection.insert(sql, name, pk, id_value)
|
27
|
-
end
|
28
|
-
|
29
|
-
def update(sql, name = nil)
|
30
|
-
clear_query_cache
|
31
|
-
@connection.update(sql, name)
|
32
|
-
end
|
33
|
-
|
34
|
-
def delete(sql, name = nil)
|
35
|
-
clear_query_cache
|
36
|
-
@connection.delete(sql, name)
|
37
|
-
end
|
38
|
-
|
39
|
-
private
|
40
|
-
def method_missing(method, *arguments, &proc)
|
41
|
-
@connection.send(method, *arguments, &proc)
|
2
|
+
module QueryCache
|
3
|
+
# Enable the query cache within the block if Active Record is configured.
|
4
|
+
def cache(&block)
|
5
|
+
if ActiveRecord::Base.configurations.blank?
|
6
|
+
yield
|
7
|
+
else
|
8
|
+
connection.cache(&block)
|
42
9
|
end
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
# Set the connection for the class with caching on
|
47
|
-
class << self
|
48
|
-
alias_method :connection_without_query_cache=, :connection=
|
10
|
+
rescue
|
11
|
+
yield # if the database is not present, don't let the cache spoil the party
|
12
|
+
end
|
49
13
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
14
|
+
# Disable the query cache within the block if Active Record is configured.
|
15
|
+
def uncached(&block)
|
16
|
+
if ActiveRecord::Base.configurations.blank?
|
17
|
+
yield
|
18
|
+
else
|
19
|
+
connection.uncached(&block)
|
55
20
|
end
|
56
21
|
end
|
57
22
|
end
|
58
|
-
|
59
|
-
class AbstractAdapter #:nodoc:
|
60
|
-
# Stub method to be able to treat the connection the same whether the query cache has been turned on or not
|
61
|
-
def clear_query_cache
|
62
|
-
end
|
63
|
-
end
|
64
23
|
end
|
@@ -44,7 +44,7 @@ module ActiveRecord
|
|
44
44
|
reflections[aggregation].is_a?(AggregateReflection) ? reflections[aggregation] : nil
|
45
45
|
end
|
46
46
|
|
47
|
-
# Returns an array of AssociationReflection objects for all the
|
47
|
+
# Returns an array of AssociationReflection objects for all the associations in the class. If you only want to reflect on a
|
48
48
|
# certain association type, pass in the symbol (:has_many, :has_one, :belongs_to) for that as the first parameter.
|
49
49
|
# Example:
|
50
50
|
#
|
@@ -56,7 +56,7 @@ module ActiveRecord
|
|
56
56
|
macro ? association_reflections.select { |reflection| reflection.macro == macro } : association_reflections
|
57
57
|
end
|
58
58
|
|
59
|
-
# Returns the AssociationReflection object for the named +
|
59
|
+
# Returns the AssociationReflection object for the named +association+ (use the symbol). Example:
|
60
60
|
#
|
61
61
|
# Account.reflect_on_association(:owner) # returns the owner AssociationReflection
|
62
62
|
# Invoice.reflect_on_association(:line_items).macro # returns :has_many
|
@@ -71,6 +71,7 @@ module ActiveRecord
|
|
71
71
|
# those classes. Objects of AggregateReflection and AssociationReflection are returned by the Reflection::ClassMethods.
|
72
72
|
class MacroReflection
|
73
73
|
attr_reader :active_record
|
74
|
+
|
74
75
|
def initialize(macro, name, options, active_record)
|
75
76
|
@macro, @name, @options, @active_record = macro, name, options, active_record
|
76
77
|
end
|
@@ -81,7 +82,7 @@ module ActiveRecord
|
|
81
82
|
@name
|
82
83
|
end
|
83
84
|
|
84
|
-
# Returns the
|
85
|
+
# Returns the type of the macro, so it would return :composed_of for
|
85
86
|
# "composed_of :balance, :class_name => 'Money'" or :has_many for "has_many :clients".
|
86
87
|
def macro
|
87
88
|
@macro
|
@@ -93,30 +94,29 @@ module ActiveRecord
|
|
93
94
|
@options
|
94
95
|
end
|
95
96
|
|
96
|
-
# Returns the class for the macro, so "composed_of :balance, :class_name => 'Money'"
|
97
|
-
# "has_many :clients"
|
98
|
-
def klass
|
99
|
-
|
97
|
+
# Returns the class for the macro, so "composed_of :balance, :class_name => 'Money'" returns the Money class and
|
98
|
+
# "has_many :clients" returns the Client class.
|
99
|
+
def klass
|
100
|
+
@klass ||= class_name.constantize
|
101
|
+
end
|
102
|
+
|
100
103
|
def class_name
|
101
|
-
@class_name ||=
|
104
|
+
@class_name ||= options[:class_name] || derive_class_name
|
102
105
|
end
|
103
106
|
|
104
107
|
def ==(other_aggregation)
|
105
108
|
name == other_aggregation.name && other_aggregation.options && active_record == other_aggregation.active_record
|
106
109
|
end
|
110
|
+
|
111
|
+
private
|
112
|
+
def derive_class_name
|
113
|
+
name.to_s.camelize
|
114
|
+
end
|
107
115
|
end
|
108
116
|
|
109
117
|
|
110
118
|
# Holds all the meta-data about an aggregation as it was specified in the Active Record class.
|
111
119
|
class AggregateReflection < MacroReflection #:nodoc:
|
112
|
-
def klass
|
113
|
-
@klass ||= Object.const_get(options[:class_name] || class_name)
|
114
|
-
end
|
115
|
-
|
116
|
-
private
|
117
|
-
def name_to_class_name(name)
|
118
|
-
name.capitalize.gsub(/_(.)/) { |s| $1.capitalize }
|
119
|
-
end
|
120
120
|
end
|
121
121
|
|
122
122
|
# Holds all the meta-data about an association as it was specified in the Active Record class.
|
@@ -130,17 +130,9 @@ module ActiveRecord
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def primary_key_name
|
133
|
-
|
134
|
-
case
|
135
|
-
when macro == :belongs_to
|
136
|
-
@primary_key_name = options[:foreign_key] || class_name.foreign_key
|
137
|
-
when options[:as]
|
138
|
-
@primary_key_name = options[:foreign_key] || "#{options[:as]}_id"
|
139
|
-
else
|
140
|
-
@primary_key_name = options[:foreign_key] || active_record.name.foreign_key
|
141
|
-
end
|
133
|
+
@primary_key_name ||= options[:foreign_key] || derive_primary_key_name
|
142
134
|
end
|
143
|
-
|
135
|
+
|
144
136
|
def association_foreign_key
|
145
137
|
@association_foreign_key ||= @options[:association_foreign_key] || class_name.foreign_key
|
146
138
|
end
|
@@ -202,19 +194,24 @@ module ActiveRecord
|
|
202
194
|
end
|
203
195
|
|
204
196
|
private
|
205
|
-
def
|
206
|
-
|
207
|
-
|
197
|
+
def derive_class_name
|
198
|
+
# get the class_name of the belongs_to association of the through reflection
|
199
|
+
if through_reflection
|
200
|
+
options[:source_type] || source_reflection.class_name
|
201
|
+
else
|
202
|
+
class_name = name.to_s.camelize
|
203
|
+
class_name = class_name.singularize if [ :has_many, :has_and_belongs_to_many ].include?(macro)
|
204
|
+
class_name
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def derive_primary_key_name
|
209
|
+
if macro == :belongs_to
|
210
|
+
"#{name}_id"
|
211
|
+
elsif options[:as]
|
212
|
+
"#{options[:as]}_id"
|
208
213
|
else
|
209
|
-
|
210
|
-
options[:class_name]
|
211
|
-
elsif through_reflection # get the class_name of the belongs_to association of the through reflection
|
212
|
-
options[:source_type] || source_reflection.class_name
|
213
|
-
else
|
214
|
-
class_name = name.to_s.camelize
|
215
|
-
class_name = class_name.singularize if [ :has_many, :has_and_belongs_to_many ].include?(macro)
|
216
|
-
class_name
|
217
|
-
end
|
214
|
+
active_record.name.foreign_key
|
218
215
|
end
|
219
216
|
end
|
220
217
|
end
|
data/lib/active_record/schema.rb
CHANGED
@@ -8,16 +8,16 @@ module ActiveRecord
|
|
8
8
|
#
|
9
9
|
# ActiveRecord::Schema.define do
|
10
10
|
# create_table :authors do |t|
|
11
|
-
# t.
|
11
|
+
# t.string :name, :null => false
|
12
12
|
# end
|
13
13
|
#
|
14
14
|
# add_index :authors, :name, :unique
|
15
15
|
#
|
16
16
|
# create_table :posts do |t|
|
17
|
-
# t.
|
18
|
-
# t.
|
19
|
-
# t.
|
20
|
-
# t.
|
17
|
+
# t.integer :author_id, :null => false
|
18
|
+
# t.string :subject
|
19
|
+
# t.text :body
|
20
|
+
# t.boolean :private, :default => false
|
21
21
|
# end
|
22
22
|
#
|
23
23
|
# add_index :posts, :author_id
|
@@ -37,9 +37,16 @@ module ActiveRecord
|
|
37
37
|
define_params = @info ? ":version => #{@info['version']}" : ""
|
38
38
|
|
39
39
|
stream.puts <<HEADER
|
40
|
-
# This file is
|
41
|
-
# migrations feature of ActiveRecord to incrementally modify your database, and
|
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 ActiveRecord to incrementally modify your database, and
|
42
42
|
# then regenerate this schema definition.
|
43
|
+
#
|
44
|
+
# Note that this schema.rb definition is the authoritative source for your database schema. If you need
|
45
|
+
# to create the application database on another system, you should be using db:schema:load, not running
|
46
|
+
# all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
47
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
48
|
+
#
|
49
|
+
# It's strongly recommended to check this file into your version control system.
|
43
50
|
|
44
51
|
ActiveRecord::Schema.define(#{define_params}) do
|
45
52
|
|
@@ -54,8 +61,8 @@ HEADER
|
|
54
61
|
@connection.tables.sort.each do |tbl|
|
55
62
|
next if ["schema_info", ignore_tables].flatten.any? do |ignored|
|
56
63
|
case ignored
|
57
|
-
when String
|
58
|
-
when Regexp
|
64
|
+
when String; tbl == ignored
|
65
|
+
when Regexp; tbl =~ ignored
|
59
66
|
else
|
60
67
|
raise StandardError, 'ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values.'
|
61
68
|
end
|
@@ -89,22 +96,37 @@ HEADER
|
|
89
96
|
raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
|
90
97
|
next if column.name == pk
|
91
98
|
spec = {}
|
92
|
-
spec[:name]
|
93
|
-
spec[:type]
|
94
|
-
spec[:limit]
|
99
|
+
spec[:name] = column.name.inspect
|
100
|
+
spec[:type] = column.type.to_s
|
101
|
+
spec[:limit] = column.limit.inspect if column.limit != @types[column.type][:limit] && column.type != :decimal
|
95
102
|
spec[:precision] = column.precision.inspect if !column.precision.nil?
|
96
|
-
spec[:scale]
|
97
|
-
spec[:null]
|
98
|
-
spec[:default]
|
103
|
+
spec[:scale] = column.scale.inspect if !column.scale.nil?
|
104
|
+
spec[:null] = 'false' if !column.null
|
105
|
+
spec[:default] = default_string(column.default) if !column.default.nil?
|
99
106
|
(spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
|
100
107
|
spec
|
101
108
|
end.compact
|
102
|
-
|
109
|
+
|
110
|
+
# find all migration keys used in this table
|
111
|
+
keys = [:name, :limit, :precision, :scale, :default, :null] & column_specs.map(&:keys).flatten
|
112
|
+
|
113
|
+
# figure out the lengths for each column based on above keys
|
103
114
|
lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }
|
104
|
-
|
115
|
+
|
116
|
+
# the string we're going to sprintf our values against, with standardized column widths
|
117
|
+
format_string = lengths.map{ |len| "%-#{len}s" }
|
118
|
+
|
119
|
+
# find the max length for the 'type' column, which is special
|
120
|
+
type_length = column_specs.map{ |column| column[:type].length }.max
|
121
|
+
|
122
|
+
# add column type definition to our format string
|
123
|
+
format_string.unshift " t.%-#{type_length}s "
|
124
|
+
|
125
|
+
format_string *= ''
|
126
|
+
|
105
127
|
column_specs.each do |colspec|
|
106
128
|
values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
|
107
|
-
|
129
|
+
values.unshift colspec[:type]
|
108
130
|
tbl.print((format_string % values).gsub(/,\s*$/, ''))
|
109
131
|
tbl.puts
|
110
132
|
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module ActiveRecord #:nodoc:
|
2
|
+
module Serialization
|
3
|
+
class Serializer #:nodoc:
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
def initialize(record, options = {})
|
7
|
+
@record, @options = record, options.dup
|
8
|
+
end
|
9
|
+
|
10
|
+
# To replicate the behavior in ActiveRecord#attributes,
|
11
|
+
# :except takes precedence over :only. If :only is not set
|
12
|
+
# for a N level model but is set for the N+1 level models,
|
13
|
+
# then because :except is set to a default value, the second
|
14
|
+
# level model can have both :except and :only set. So if
|
15
|
+
# :only is set, always delete :except.
|
16
|
+
def serializable_attribute_names
|
17
|
+
attribute_names = @record.attribute_names
|
18
|
+
|
19
|
+
if options[:only]
|
20
|
+
options.delete(:except)
|
21
|
+
attribute_names = attribute_names & Array(options[:only]).collect { |n| n.to_s }
|
22
|
+
else
|
23
|
+
options[:except] = Array(options[:except]) | Array(@record.class.inheritance_column)
|
24
|
+
attribute_names = attribute_names - options[:except].collect { |n| n.to_s }
|
25
|
+
end
|
26
|
+
|
27
|
+
attribute_names
|
28
|
+
end
|
29
|
+
|
30
|
+
def serializable_method_names
|
31
|
+
Array(options[:methods]).inject([]) do |method_attributes, name|
|
32
|
+
method_attributes << name if @record.respond_to?(name.to_s)
|
33
|
+
method_attributes
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def serializable_names
|
38
|
+
serializable_attribute_names + serializable_method_names
|
39
|
+
end
|
40
|
+
|
41
|
+
# Add associations specified via the :includes option.
|
42
|
+
# Expects a block that takes as arguments:
|
43
|
+
# +association+ - name of the association
|
44
|
+
# +records+ - the association record(s) to be serialized
|
45
|
+
# +opts+ - options for the association records
|
46
|
+
def add_includes(&block)
|
47
|
+
if include_associations = options.delete(:include)
|
48
|
+
base_only_or_except = { :except => options[:except],
|
49
|
+
:only => options[:only] }
|
50
|
+
|
51
|
+
include_has_options = include_associations.is_a?(Hash)
|
52
|
+
associations = include_has_options ? include_associations.keys : Array(include_associations)
|
53
|
+
|
54
|
+
for association in associations
|
55
|
+
records = case @record.class.reflect_on_association(association).macro
|
56
|
+
when :has_many, :has_and_belongs_to_many
|
57
|
+
@record.send(association).to_a
|
58
|
+
when :has_one, :belongs_to
|
59
|
+
@record.send(association)
|
60
|
+
end
|
61
|
+
|
62
|
+
unless records.nil?
|
63
|
+
association_options = include_has_options ? include_associations[association] : base_only_or_except
|
64
|
+
opts = options.merge(association_options)
|
65
|
+
yield(association, records, opts)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
options[:include] = include_associations
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def serializable_record
|
74
|
+
returning(serializable_record = {}) do
|
75
|
+
serializable_names.each { |name| serializable_record[name] = @record.send(name) }
|
76
|
+
add_includes do |association, records, opts|
|
77
|
+
if records.is_a?(Enumerable)
|
78
|
+
serializable_record[association] = records.collect { |r| self.class.new(r, opts).serializable_record }
|
79
|
+
else
|
80
|
+
serializable_record[association] = self.class.new(records, opts).serializable_record
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def serialize
|
87
|
+
# overwrite to implement
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_s(&block)
|
91
|
+
serialize(&block)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
require 'active_record/serializers/xml_serializer'
|
98
|
+
require 'active_record/serializers/json_serializer'
|