activerecord 3.0.0 → 4.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +2102 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +35 -44
- data/examples/performance.rb +110 -100
- data/lib/active_record/aggregations.rb +59 -75
- data/lib/active_record/associations/alias_tracker.rb +76 -0
- data/lib/active_record/associations/association.rb +248 -0
- data/lib/active_record/associations/association_scope.rb +135 -0
- data/lib/active_record/associations/belongs_to_association.rb +60 -59
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +16 -59
- data/lib/active_record/associations/builder/association.rb +108 -0
- data/lib/active_record/associations/builder/belongs_to.rb +98 -0
- data/lib/active_record/associations/builder/collection_association.rb +89 -0
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +39 -0
- data/lib/active_record/associations/builder/has_many.rb +15 -0
- data/lib/active_record/associations/builder/has_one.rb +25 -0
- data/lib/active_record/associations/builder/singular_association.rb +32 -0
- data/lib/active_record/associations/collection_association.rb +608 -0
- data/lib/active_record/associations/collection_proxy.rb +986 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +40 -112
- data/lib/active_record/associations/has_many_association.rb +83 -76
- data/lib/active_record/associations/has_many_through_association.rb +147 -66
- data/lib/active_record/associations/has_one_association.rb +67 -108
- data/lib/active_record/associations/has_one_through_association.rb +21 -25
- data/lib/active_record/associations/join_dependency/join_association.rb +174 -0
- data/lib/active_record/associations/join_dependency/join_base.rb +24 -0
- data/lib/active_record/associations/join_dependency/join_part.rb +78 -0
- data/lib/active_record/associations/join_dependency.rb +235 -0
- data/lib/active_record/associations/join_helper.rb +45 -0
- data/lib/active_record/associations/preloader/association.rb +121 -0
- data/lib/active_record/associations/preloader/belongs_to.rb +17 -0
- data/lib/active_record/associations/preloader/collection_association.rb +24 -0
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +60 -0
- data/lib/active_record/associations/preloader/has_many.rb +17 -0
- data/lib/active_record/associations/preloader/has_many_through.rb +19 -0
- data/lib/active_record/associations/preloader/has_one.rb +23 -0
- data/lib/active_record/associations/preloader/has_one_through.rb +9 -0
- data/lib/active_record/associations/preloader/singular_association.rb +21 -0
- data/lib/active_record/associations/preloader/through_association.rb +63 -0
- data/lib/active_record/associations/preloader.rb +178 -0
- data/lib/active_record/associations/singular_association.rb +64 -0
- data/lib/active_record/associations/through_association.rb +87 -0
- data/lib/active_record/associations.rb +512 -1224
- data/lib/active_record/attribute_assignment.rb +201 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +49 -12
- data/lib/active_record/attribute_methods/dirty.rb +51 -28
- data/lib/active_record/attribute_methods/primary_key.rb +94 -22
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +63 -72
- data/lib/active_record/attribute_methods/serialization.rb +162 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -41
- data/lib/active_record/attribute_methods/write.rb +39 -13
- data/lib/active_record/attribute_methods.rb +362 -29
- data/lib/active_record/autosave_association.rb +132 -75
- data/lib/active_record/base.rb +83 -1627
- data/lib/active_record/callbacks.rb +69 -47
- data/lib/active_record/coders/yaml_column.rb +38 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +411 -138
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +21 -11
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +234 -173
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +36 -22
- data/lib/active_record/connection_adapters/abstract/quoting.rb +82 -25
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +176 -414
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +70 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +562 -232
- data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +281 -53
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +782 -0
- data/lib/active_record/connection_adapters/column.rb +318 -0
- data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +273 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +365 -450
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/cast.rb +152 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +366 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +171 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +489 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +672 -752
- data/lib/active_record/connection_adapters/schema_cache.rb +129 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +588 -17
- data/lib/active_record/connection_adapters/statement_pool.rb +40 -0
- data/lib/active_record/connection_handling.rb +98 -0
- data/lib/active_record/core.rb +463 -0
- data/lib/active_record/counter_cache.rb +108 -101
- data/lib/active_record/dynamic_matchers.rb +131 -0
- data/lib/active_record/errors.rb +54 -13
- data/lib/active_record/explain.rb +38 -0
- data/lib/active_record/explain_registry.rb +30 -0
- data/lib/active_record/explain_subscriber.rb +29 -0
- data/lib/active_record/fixture_set/file.rb +55 -0
- data/lib/active_record/fixtures.rb +703 -785
- data/lib/active_record/inheritance.rb +200 -0
- data/lib/active_record/integration.rb +60 -0
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +69 -60
- data/lib/active_record/locking/pessimistic.rb +34 -12
- data/lib/active_record/log_subscriber.rb +40 -6
- data/lib/active_record/migration/command_recorder.rb +164 -0
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/migration.rb +614 -216
- data/lib/active_record/model_schema.rb +345 -0
- data/lib/active_record/nested_attributes.rb +248 -119
- data/lib/active_record/null_relation.rb +65 -0
- data/lib/active_record/persistence.rb +275 -57
- data/lib/active_record/query_cache.rb +29 -9
- data/lib/active_record/querying.rb +62 -0
- data/lib/active_record/railtie.rb +135 -21
- data/lib/active_record/railties/console_sandbox.rb +5 -0
- data/lib/active_record/railties/controller_runtime.rb +17 -5
- data/lib/active_record/railties/databases.rake +249 -359
- data/lib/active_record/railties/jdbcmysql_error.rb +16 -0
- data/lib/active_record/readonly_attributes.rb +30 -0
- data/lib/active_record/reflection.rb +283 -103
- data/lib/active_record/relation/batches.rb +38 -34
- data/lib/active_record/relation/calculations.rb +252 -139
- data/lib/active_record/relation/delegation.rb +125 -0
- data/lib/active_record/relation/finder_methods.rb +182 -188
- data/lib/active_record/relation/merger.rb +161 -0
- data/lib/active_record/relation/predicate_builder.rb +86 -21
- data/lib/active_record/relation/query_methods.rb +917 -134
- data/lib/active_record/relation/spawn_methods.rb +53 -92
- data/lib/active_record/relation.rb +405 -143
- data/lib/active_record/result.rb +67 -0
- data/lib/active_record/runtime_registry.rb +17 -0
- data/lib/active_record/sanitization.rb +168 -0
- data/lib/active_record/schema.rb +20 -14
- data/lib/active_record/schema_dumper.rb +55 -46
- data/lib/active_record/schema_migration.rb +39 -0
- data/lib/active_record/scoping/default.rb +146 -0
- data/lib/active_record/scoping/named.rb +175 -0
- data/lib/active_record/scoping.rb +82 -0
- data/lib/active_record/serialization.rb +8 -46
- data/lib/active_record/serializers/xml_serializer.rb +21 -68
- data/lib/active_record/statement_cache.rb +26 -0
- data/lib/active_record/store.rb +156 -0
- data/lib/active_record/tasks/database_tasks.rb +203 -0
- data/lib/active_record/tasks/firebird_database_tasks.rb +56 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +143 -0
- data/lib/active_record/tasks/oracle_database_tasks.rb +45 -0
- data/lib/active_record/tasks/postgresql_database_tasks.rb +90 -0
- data/lib/active_record/tasks/sqlite_database_tasks.rb +51 -0
- data/lib/active_record/tasks/sqlserver_database_tasks.rb +48 -0
- data/lib/active_record/test_case.rb +57 -28
- data/lib/active_record/timestamp.rb +49 -18
- data/lib/active_record/transactions.rb +106 -63
- data/lib/active_record/translation.rb +22 -0
- data/lib/active_record/validations/associated.rb +25 -24
- data/lib/active_record/validations/presence.rb +65 -0
- data/lib/active_record/validations/uniqueness.rb +123 -83
- data/lib/active_record/validations.rb +29 -29
- data/lib/active_record/version.rb +7 -5
- data/lib/active_record.rb +83 -34
- data/lib/rails/generators/active_record/migration/migration_generator.rb +46 -9
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +19 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +30 -8
- data/lib/rails/generators/active_record/model/model_generator.rb +15 -5
- data/lib/rails/generators/active_record/model/templates/model.rb +7 -2
- data/lib/rails/generators/active_record/model/templates/module.rb +3 -1
- data/lib/rails/generators/active_record.rb +4 -8
- metadata +163 -121
- data/CHANGELOG +0 -6023
- data/examples/associations.png +0 -0
- data/lib/active_record/association_preload.rb +0 -403
- data/lib/active_record/associations/association_collection.rb +0 -562
- data/lib/active_record/associations/association_proxy.rb +0 -295
- data/lib/active_record/associations/through_association_scope.rb +0 -154
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -113
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -401
- data/lib/active_record/dynamic_finder_match.rb +0 -53
- data/lib/active_record/dynamic_scope_match.rb +0 -32
- data/lib/active_record/named_scope.rb +0 -138
- data/lib/active_record/observer.rb +0 -140
- data/lib/active_record/session_store.rb +0 -340
- data/lib/rails/generators/active_record/model/templates/migration.rb +0 -16
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -2
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -24
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -16
@@ -1,295 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/array/wrap'
|
2
|
-
|
3
|
-
module ActiveRecord
|
4
|
-
module Associations
|
5
|
-
# = Active Record Associations
|
6
|
-
#
|
7
|
-
# This is the root class of all association proxies:
|
8
|
-
#
|
9
|
-
# AssociationProxy
|
10
|
-
# BelongsToAssociation
|
11
|
-
# HasOneAssociation
|
12
|
-
# BelongsToPolymorphicAssociation
|
13
|
-
# AssociationCollection
|
14
|
-
# HasAndBelongsToManyAssociation
|
15
|
-
# HasManyAssociation
|
16
|
-
# HasManyThroughAssociation
|
17
|
-
# HasOneThroughAssociation
|
18
|
-
#
|
19
|
-
# Association proxies in Active Record are middlemen between the object that
|
20
|
-
# holds the association, known as the <tt>@owner</tt>, and the actual associated
|
21
|
-
# object, known as the <tt>@target</tt>. The kind of association any proxy is
|
22
|
-
# about is available in <tt>@reflection</tt>. That's an instance of the class
|
23
|
-
# ActiveRecord::Reflection::AssociationReflection.
|
24
|
-
#
|
25
|
-
# For example, given
|
26
|
-
#
|
27
|
-
# class Blog < ActiveRecord::Base
|
28
|
-
# has_many :posts
|
29
|
-
# end
|
30
|
-
#
|
31
|
-
# blog = Blog.find(:first)
|
32
|
-
#
|
33
|
-
# the association proxy in <tt>blog.posts</tt> has the object in +blog+ as
|
34
|
-
# <tt>@owner</tt>, the collection of its posts as <tt>@target</tt>, and
|
35
|
-
# the <tt>@reflection</tt> object represents a <tt>:has_many</tt> macro.
|
36
|
-
#
|
37
|
-
# This class has most of the basic instance methods removed, and delegates
|
38
|
-
# unknown methods to <tt>@target</tt> via <tt>method_missing</tt>. As a
|
39
|
-
# corner case, it even removes the +class+ method and that's why you get
|
40
|
-
#
|
41
|
-
# blog.posts.class # => Array
|
42
|
-
#
|
43
|
-
# though the object behind <tt>blog.posts</tt> is not an Array, but an
|
44
|
-
# ActiveRecord::Associations::HasManyAssociation.
|
45
|
-
#
|
46
|
-
# The <tt>@target</tt> object is not \loaded until needed. For example,
|
47
|
-
#
|
48
|
-
# blog.posts.count
|
49
|
-
#
|
50
|
-
# is computed directly through SQL and does not trigger by itself the
|
51
|
-
# instantiation of the actual post records.
|
52
|
-
class AssociationProxy #:nodoc:
|
53
|
-
alias_method :proxy_respond_to?, :respond_to?
|
54
|
-
alias_method :proxy_extend, :extend
|
55
|
-
delegate :to_param, :to => :proxy_target
|
56
|
-
instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|proxy_/ }
|
57
|
-
|
58
|
-
def initialize(owner, reflection)
|
59
|
-
@owner, @reflection = owner, reflection
|
60
|
-
@updated = false
|
61
|
-
reflection.check_validity!
|
62
|
-
Array.wrap(reflection.options[:extend]).each { |ext| proxy_extend(ext) }
|
63
|
-
reset
|
64
|
-
end
|
65
|
-
|
66
|
-
# Returns the owner of the proxy.
|
67
|
-
def proxy_owner
|
68
|
-
@owner
|
69
|
-
end
|
70
|
-
|
71
|
-
# Returns the reflection object that represents the association handled
|
72
|
-
# by the proxy.
|
73
|
-
def proxy_reflection
|
74
|
-
@reflection
|
75
|
-
end
|
76
|
-
|
77
|
-
# Returns the \target of the proxy, same as +target+.
|
78
|
-
def proxy_target
|
79
|
-
@target
|
80
|
-
end
|
81
|
-
|
82
|
-
# Does the proxy or its \target respond to +symbol+?
|
83
|
-
def respond_to?(*args)
|
84
|
-
proxy_respond_to?(*args) || (load_target && @target.respond_to?(*args))
|
85
|
-
end
|
86
|
-
|
87
|
-
# Forwards <tt>===</tt> explicitly to the \target because the instance method
|
88
|
-
# removal above doesn't catch it. Loads the \target if needed.
|
89
|
-
def ===(other)
|
90
|
-
load_target
|
91
|
-
other === @target
|
92
|
-
end
|
93
|
-
|
94
|
-
# Returns the name of the table of the related class:
|
95
|
-
#
|
96
|
-
# post.comments.aliased_table_name # => "comments"
|
97
|
-
#
|
98
|
-
def aliased_table_name
|
99
|
-
@reflection.klass.table_name
|
100
|
-
end
|
101
|
-
|
102
|
-
# Returns the SQL string that corresponds to the <tt>:conditions</tt>
|
103
|
-
# option of the macro, if given, or +nil+ otherwise.
|
104
|
-
def conditions
|
105
|
-
@conditions ||= interpolate_sql(@reflection.sanitized_conditions) if @reflection.sanitized_conditions
|
106
|
-
end
|
107
|
-
alias :sql_conditions :conditions
|
108
|
-
|
109
|
-
# Resets the \loaded flag to +false+ and sets the \target to +nil+.
|
110
|
-
def reset
|
111
|
-
@loaded = false
|
112
|
-
@target = nil
|
113
|
-
end
|
114
|
-
|
115
|
-
# Reloads the \target and returns +self+ on success.
|
116
|
-
def reload
|
117
|
-
reset
|
118
|
-
load_target
|
119
|
-
self unless @target.nil?
|
120
|
-
end
|
121
|
-
|
122
|
-
# Has the \target been already \loaded?
|
123
|
-
def loaded?
|
124
|
-
@loaded
|
125
|
-
end
|
126
|
-
|
127
|
-
# Asserts the \target has been loaded setting the \loaded flag to +true+.
|
128
|
-
def loaded
|
129
|
-
@loaded = true
|
130
|
-
end
|
131
|
-
|
132
|
-
# Returns the target of this proxy, same as +proxy_target+.
|
133
|
-
def target
|
134
|
-
@target
|
135
|
-
end
|
136
|
-
|
137
|
-
# Sets the target of this proxy to <tt>\target</tt>, and the \loaded flag to +true+.
|
138
|
-
def target=(target)
|
139
|
-
@target = target
|
140
|
-
loaded
|
141
|
-
end
|
142
|
-
|
143
|
-
# Forwards the call to the target. Loads the \target if needed.
|
144
|
-
def inspect
|
145
|
-
load_target
|
146
|
-
@target.inspect
|
147
|
-
end
|
148
|
-
|
149
|
-
def send(method, *args)
|
150
|
-
if proxy_respond_to?(method)
|
151
|
-
super
|
152
|
-
else
|
153
|
-
load_target
|
154
|
-
@target.send(method, *args)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
|
-
protected
|
159
|
-
# Does the association have a <tt>:dependent</tt> option?
|
160
|
-
def dependent?
|
161
|
-
@reflection.options[:dependent]
|
162
|
-
end
|
163
|
-
|
164
|
-
def interpolate_sql(sql, record = nil)
|
165
|
-
@owner.send(:interpolate_sql, sql, record)
|
166
|
-
end
|
167
|
-
|
168
|
-
# Forwards the call to the reflection class.
|
169
|
-
def sanitize_sql(sql, table_name = @reflection.klass.table_name)
|
170
|
-
@reflection.klass.send(:sanitize_sql, sql, table_name)
|
171
|
-
end
|
172
|
-
|
173
|
-
# Assigns the ID of the owner to the corresponding foreign key in +record+.
|
174
|
-
# If the association is polymorphic the type of the owner is also set.
|
175
|
-
def set_belongs_to_association_for(record)
|
176
|
-
if @reflection.options[:as]
|
177
|
-
record["#{@reflection.options[:as]}_id"] = @owner.id unless @owner.new_record?
|
178
|
-
record["#{@reflection.options[:as]}_type"] = @owner.class.base_class.name.to_s
|
179
|
-
else
|
180
|
-
unless @owner.new_record?
|
181
|
-
primary_key = @reflection.options[:primary_key] || :id
|
182
|
-
record[@reflection.primary_key_name] = @owner.send(primary_key)
|
183
|
-
end
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
# Merges into +options+ the ones coming from the reflection.
|
188
|
-
def merge_options_from_reflection!(options)
|
189
|
-
options.reverse_merge!(
|
190
|
-
:group => @reflection.options[:group],
|
191
|
-
:having => @reflection.options[:having],
|
192
|
-
:limit => @reflection.options[:limit],
|
193
|
-
:offset => @reflection.options[:offset],
|
194
|
-
:joins => @reflection.options[:joins],
|
195
|
-
:include => @reflection.options[:include],
|
196
|
-
:select => @reflection.options[:select],
|
197
|
-
:readonly => @reflection.options[:readonly]
|
198
|
-
)
|
199
|
-
end
|
200
|
-
|
201
|
-
# Forwards +with_scope+ to the reflection.
|
202
|
-
def with_scope(*args, &block)
|
203
|
-
@reflection.klass.send :with_scope, *args, &block
|
204
|
-
end
|
205
|
-
|
206
|
-
private
|
207
|
-
# Forwards any missing method call to the \target.
|
208
|
-
def method_missing(method, *args)
|
209
|
-
if load_target
|
210
|
-
unless @target.respond_to?(method)
|
211
|
-
message = "undefined method `#{method.to_s}' for \"#{@target}\":#{@target.class.to_s}"
|
212
|
-
raise NoMethodError, message
|
213
|
-
end
|
214
|
-
|
215
|
-
if block_given?
|
216
|
-
@target.send(method, *args) { |*block_args| yield(*block_args) }
|
217
|
-
else
|
218
|
-
@target.send(method, *args)
|
219
|
-
end
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
# Loads the \target if needed and returns it.
|
224
|
-
#
|
225
|
-
# This method is abstract in the sense that it relies on +find_target+,
|
226
|
-
# which is expected to be provided by descendants.
|
227
|
-
#
|
228
|
-
# If the \target is already \loaded it is just returned. Thus, you can call
|
229
|
-
# +load_target+ unconditionally to get the \target.
|
230
|
-
#
|
231
|
-
# ActiveRecord::RecordNotFound is rescued within the method, and it is
|
232
|
-
# not reraised. The proxy is \reset and +nil+ is the return value.
|
233
|
-
def load_target
|
234
|
-
return nil unless defined?(@loaded)
|
235
|
-
|
236
|
-
if !loaded? and (!@owner.new_record? || foreign_key_present)
|
237
|
-
@target = find_target
|
238
|
-
end
|
239
|
-
|
240
|
-
@loaded = true
|
241
|
-
@target
|
242
|
-
rescue ActiveRecord::RecordNotFound
|
243
|
-
reset
|
244
|
-
end
|
245
|
-
|
246
|
-
# Can be overwritten by associations that might have the foreign key
|
247
|
-
# available for an association without having the object itself (and
|
248
|
-
# still being a new record). Currently, only +belongs_to+ presents
|
249
|
-
# this scenario (both vanilla and polymorphic).
|
250
|
-
def foreign_key_present
|
251
|
-
false
|
252
|
-
end
|
253
|
-
|
254
|
-
# Raises ActiveRecord::AssociationTypeMismatch unless +record+ is of
|
255
|
-
# the kind of the class of the associated objects. Meant to be used as
|
256
|
-
# a sanity check when you are about to assign an associated record.
|
257
|
-
def raise_on_type_mismatch(record)
|
258
|
-
unless record.is_a?(@reflection.klass) || record.is_a?(@reflection.class_name.constantize)
|
259
|
-
message = "#{@reflection.class_name}(##{@reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
|
260
|
-
raise ActiveRecord::AssociationTypeMismatch, message
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
if RUBY_VERSION < '1.9.2'
|
265
|
-
# Array#flatten has problems with recursive arrays before Ruby 1.9.2.
|
266
|
-
# Going one level deeper solves the majority of the problems.
|
267
|
-
def flatten_deeper(array)
|
268
|
-
array.collect { |element| (element.respond_to?(:flatten) && !element.is_a?(Hash)) ? element.flatten : element }.flatten
|
269
|
-
end
|
270
|
-
else
|
271
|
-
def flatten_deeper(array)
|
272
|
-
array.flatten
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
# Returns the ID of the owner, quoted if needed.
|
277
|
-
def owner_quoted_id
|
278
|
-
@owner.quoted_id
|
279
|
-
end
|
280
|
-
|
281
|
-
def set_inverse_instance(record, instance)
|
282
|
-
return if record.nil? || !we_can_set_the_inverse_on_this?(record)
|
283
|
-
inverse_relationship = @reflection.inverse_of
|
284
|
-
unless inverse_relationship.nil?
|
285
|
-
record.send(:"set_#{inverse_relationship.name}_target", instance)
|
286
|
-
end
|
287
|
-
end
|
288
|
-
|
289
|
-
# Override in subclasses
|
290
|
-
def we_can_set_the_inverse_on_this?(record)
|
291
|
-
false
|
292
|
-
end
|
293
|
-
end
|
294
|
-
end
|
295
|
-
end
|
@@ -1,154 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
# = Active Record Through Association Scope
|
3
|
-
module Associations
|
4
|
-
module ThroughAssociationScope
|
5
|
-
|
6
|
-
protected
|
7
|
-
|
8
|
-
def construct_scope
|
9
|
-
{ :create => construct_owner_attributes(@reflection),
|
10
|
-
:find => { :conditions => construct_conditions,
|
11
|
-
:joins => construct_joins,
|
12
|
-
:include => @reflection.options[:include] || @reflection.source_reflection.options[:include],
|
13
|
-
:select => construct_select,
|
14
|
-
:order => @reflection.options[:order],
|
15
|
-
:limit => @reflection.options[:limit],
|
16
|
-
:readonly => @reflection.options[:readonly],
|
17
|
-
} }
|
18
|
-
end
|
19
|
-
|
20
|
-
# Build SQL conditions from attributes, qualified by table name.
|
21
|
-
def construct_conditions
|
22
|
-
table_name = @reflection.through_reflection.quoted_table_name
|
23
|
-
conditions = construct_quoted_owner_attributes(@reflection.through_reflection).map do |attr, value|
|
24
|
-
"#{table_name}.#{attr} = #{value}"
|
25
|
-
end
|
26
|
-
conditions << sql_conditions if sql_conditions
|
27
|
-
"(" + conditions.join(') AND (') + ")"
|
28
|
-
end
|
29
|
-
|
30
|
-
# Associate attributes pointing to owner, quoted.
|
31
|
-
def construct_quoted_owner_attributes(reflection)
|
32
|
-
if as = reflection.options[:as]
|
33
|
-
{ "#{as}_id" => owner_quoted_id,
|
34
|
-
"#{as}_type" => reflection.klass.quote_value(
|
35
|
-
@owner.class.base_class.name.to_s,
|
36
|
-
reflection.klass.columns_hash["#{as}_type"]) }
|
37
|
-
elsif reflection.macro == :belongs_to
|
38
|
-
{ reflection.klass.primary_key => @owner.class.quote_value(@owner[reflection.primary_key_name]) }
|
39
|
-
else
|
40
|
-
{ reflection.primary_key_name => owner_quoted_id }
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def construct_from
|
45
|
-
@reflection.table_name
|
46
|
-
end
|
47
|
-
|
48
|
-
def construct_select(custom_select = nil)
|
49
|
-
distinct = "DISTINCT " if @reflection.options[:uniq]
|
50
|
-
selected = custom_select || @reflection.options[:select] || "#{distinct}#{@reflection.quoted_table_name}.*"
|
51
|
-
end
|
52
|
-
|
53
|
-
def construct_joins(custom_joins = nil)
|
54
|
-
polymorphic_join = nil
|
55
|
-
if @reflection.source_reflection.macro == :belongs_to
|
56
|
-
reflection_primary_key = @reflection.klass.primary_key
|
57
|
-
source_primary_key = @reflection.source_reflection.primary_key_name
|
58
|
-
if @reflection.options[:source_type]
|
59
|
-
polymorphic_join = "AND %s.%s = %s" % [
|
60
|
-
@reflection.through_reflection.quoted_table_name, "#{@reflection.source_reflection.options[:foreign_type]}",
|
61
|
-
@owner.class.quote_value(@reflection.options[:source_type])
|
62
|
-
]
|
63
|
-
end
|
64
|
-
else
|
65
|
-
reflection_primary_key = @reflection.source_reflection.primary_key_name
|
66
|
-
source_primary_key = @reflection.through_reflection.klass.primary_key
|
67
|
-
if @reflection.source_reflection.options[:as]
|
68
|
-
polymorphic_join = "AND %s.%s = %s" % [
|
69
|
-
@reflection.quoted_table_name, "#{@reflection.source_reflection.options[:as]}_type",
|
70
|
-
@owner.class.quote_value(@reflection.through_reflection.klass.name)
|
71
|
-
]
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
"INNER JOIN %s ON %s.%s = %s.%s %s #{@reflection.options[:joins]} #{custom_joins}" % [
|
76
|
-
@reflection.through_reflection.quoted_table_name,
|
77
|
-
@reflection.quoted_table_name, reflection_primary_key,
|
78
|
-
@reflection.through_reflection.quoted_table_name, source_primary_key,
|
79
|
-
polymorphic_join
|
80
|
-
]
|
81
|
-
end
|
82
|
-
|
83
|
-
# Construct attributes for associate pointing to owner.
|
84
|
-
def construct_owner_attributes(reflection)
|
85
|
-
if as = reflection.options[:as]
|
86
|
-
{ "#{as}_id" => @owner.id,
|
87
|
-
"#{as}_type" => @owner.class.base_class.name.to_s }
|
88
|
-
else
|
89
|
-
{ reflection.primary_key_name => @owner.id }
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# Construct attributes for :through pointing to owner and associate.
|
94
|
-
def construct_join_attributes(associate)
|
95
|
-
# TODO: revisit this to allow it for deletion, supposing dependent option is supported
|
96
|
-
raise ActiveRecord::HasManyThroughCantAssociateThroughHasOneOrManyReflection.new(@owner, @reflection) if [:has_one, :has_many].include?(@reflection.source_reflection.macro)
|
97
|
-
|
98
|
-
join_attributes = construct_owner_attributes(@reflection.through_reflection).merge(@reflection.source_reflection.primary_key_name => associate.id)
|
99
|
-
|
100
|
-
if @reflection.options[:source_type]
|
101
|
-
join_attributes.merge!(@reflection.source_reflection.options[:foreign_type] => associate.class.base_class.name.to_s)
|
102
|
-
end
|
103
|
-
|
104
|
-
if @reflection.through_reflection.options[:conditions].is_a?(Hash)
|
105
|
-
join_attributes.merge!(@reflection.through_reflection.options[:conditions])
|
106
|
-
end
|
107
|
-
|
108
|
-
join_attributes
|
109
|
-
end
|
110
|
-
|
111
|
-
def conditions
|
112
|
-
@conditions = build_conditions unless defined?(@conditions)
|
113
|
-
@conditions
|
114
|
-
end
|
115
|
-
|
116
|
-
def build_conditions
|
117
|
-
association_conditions = @reflection.options[:conditions]
|
118
|
-
through_conditions = build_through_conditions
|
119
|
-
source_conditions = @reflection.source_reflection.options[:conditions]
|
120
|
-
uses_sti = !@reflection.through_reflection.klass.descends_from_active_record?
|
121
|
-
|
122
|
-
if association_conditions || through_conditions || source_conditions || uses_sti
|
123
|
-
all = []
|
124
|
-
|
125
|
-
[association_conditions, source_conditions].each do |conditions|
|
126
|
-
all << interpolate_sql(sanitize_sql(conditions)) if conditions
|
127
|
-
end
|
128
|
-
|
129
|
-
all << through_conditions if through_conditions
|
130
|
-
all << build_sti_condition if uses_sti
|
131
|
-
|
132
|
-
all.map { |sql| "(#{sql})" } * ' AND '
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def build_through_conditions
|
137
|
-
conditions = @reflection.through_reflection.options[:conditions]
|
138
|
-
if conditions.is_a?(Hash)
|
139
|
-
interpolate_sql(@reflection.through_reflection.klass.send(:sanitize_sql, conditions)).gsub(
|
140
|
-
@reflection.quoted_table_name,
|
141
|
-
@reflection.through_reflection.quoted_table_name)
|
142
|
-
elsif conditions
|
143
|
-
interpolate_sql(sanitize_sql(conditions))
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
def build_sti_condition
|
148
|
-
@reflection.through_reflection.klass.send(:type_condition).to_sql
|
149
|
-
end
|
150
|
-
|
151
|
-
alias_method :sql_conditions, :conditions
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
@@ -1,113 +0,0 @@
|
|
1
|
-
module ActiveRecord
|
2
|
-
class Base
|
3
|
-
class ConnectionSpecification #:nodoc:
|
4
|
-
attr_reader :config, :adapter_method
|
5
|
-
def initialize (config, adapter_method)
|
6
|
-
@config, @adapter_method = config, adapter_method
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
##
|
11
|
-
# :singleton-method:
|
12
|
-
# The connection handler
|
13
|
-
class_attribute :connection_handler, :instance_writer => false
|
14
|
-
self.connection_handler = ConnectionAdapters::ConnectionHandler.new
|
15
|
-
|
16
|
-
# Returns the connection currently associated with the class. This can
|
17
|
-
# also be used to "borrow" the connection to do database work that isn't
|
18
|
-
# easily done without going straight to SQL.
|
19
|
-
def connection
|
20
|
-
self.class.connection
|
21
|
-
end
|
22
|
-
|
23
|
-
# Establishes the connection to the database. Accepts a hash as input where
|
24
|
-
# the <tt>:adapter</tt> key must be specified with the name of a database adapter (in lower-case)
|
25
|
-
# example for regular databases (MySQL, Postgresql, etc):
|
26
|
-
#
|
27
|
-
# ActiveRecord::Base.establish_connection(
|
28
|
-
# :adapter => "mysql",
|
29
|
-
# :host => "localhost",
|
30
|
-
# :username => "myuser",
|
31
|
-
# :password => "mypass",
|
32
|
-
# :database => "somedatabase"
|
33
|
-
# )
|
34
|
-
#
|
35
|
-
# Example for SQLite database:
|
36
|
-
#
|
37
|
-
# ActiveRecord::Base.establish_connection(
|
38
|
-
# :adapter => "sqlite",
|
39
|
-
# :database => "path/to/dbfile"
|
40
|
-
# )
|
41
|
-
#
|
42
|
-
# Also accepts keys as strings (for parsing from YAML for example):
|
43
|
-
#
|
44
|
-
# ActiveRecord::Base.establish_connection(
|
45
|
-
# "adapter" => "sqlite",
|
46
|
-
# "database" => "path/to/dbfile"
|
47
|
-
# )
|
48
|
-
#
|
49
|
-
# The exceptions AdapterNotSpecified, AdapterNotFound and ArgumentError
|
50
|
-
# may be returned on an error.
|
51
|
-
def self.establish_connection(spec = nil)
|
52
|
-
case spec
|
53
|
-
when nil
|
54
|
-
raise AdapterNotSpecified unless defined?(Rails.env)
|
55
|
-
establish_connection(Rails.env)
|
56
|
-
when ConnectionSpecification
|
57
|
-
self.connection_handler.establish_connection(name, spec)
|
58
|
-
when Symbol, String
|
59
|
-
if configuration = configurations[spec.to_s]
|
60
|
-
establish_connection(configuration)
|
61
|
-
else
|
62
|
-
raise AdapterNotSpecified, "#{spec} database is not configured"
|
63
|
-
end
|
64
|
-
else
|
65
|
-
spec = spec.symbolize_keys
|
66
|
-
unless spec.key?(:adapter) then raise AdapterNotSpecified, "database configuration does not specify adapter" end
|
67
|
-
|
68
|
-
begin
|
69
|
-
require "active_record/connection_adapters/#{spec[:adapter]}_adapter"
|
70
|
-
rescue LoadError
|
71
|
-
raise "Please install the #{spec[:adapter]} adapter: `gem install activerecord-#{spec[:adapter]}-adapter` (#{$!})"
|
72
|
-
end
|
73
|
-
|
74
|
-
adapter_method = "#{spec[:adapter]}_connection"
|
75
|
-
if !respond_to?(adapter_method)
|
76
|
-
raise AdapterNotFound, "database configuration specifies nonexistent #{spec[:adapter]} adapter"
|
77
|
-
end
|
78
|
-
|
79
|
-
remove_connection
|
80
|
-
establish_connection(ConnectionSpecification.new(spec, adapter_method))
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
class << self
|
85
|
-
# Returns the connection currently associated with the class. This can
|
86
|
-
# also be used to "borrow" the connection to do database work unrelated
|
87
|
-
# to any of the specific Active Records.
|
88
|
-
def connection
|
89
|
-
retrieve_connection
|
90
|
-
end
|
91
|
-
|
92
|
-
def connection_pool
|
93
|
-
connection_handler.retrieve_connection_pool(self)
|
94
|
-
end
|
95
|
-
|
96
|
-
def retrieve_connection
|
97
|
-
connection_handler.retrieve_connection(self)
|
98
|
-
end
|
99
|
-
|
100
|
-
# Returns true if Active Record is connected.
|
101
|
-
def connected?
|
102
|
-
connection_handler.connected?(self)
|
103
|
-
end
|
104
|
-
|
105
|
-
def remove_connection(klass = self)
|
106
|
-
connection_handler.remove_connection(klass)
|
107
|
-
end
|
108
|
-
|
109
|
-
delegate :clear_active_connections!, :clear_reloadable_connections!,
|
110
|
-
:clear_all_connections!,:verify_active_connections!, :to => :connection_handler
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|