activerecord 4.1.16 → 4.2.0.beta1
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 +4 -4
- data/CHANGELOG.md +634 -2185
- data/README.rdoc +15 -10
- data/lib/active_record.rb +2 -1
- data/lib/active_record/aggregations.rb +12 -8
- data/lib/active_record/associations.rb +58 -33
- data/lib/active_record/associations/association.rb +1 -1
- data/lib/active_record/associations/association_scope.rb +53 -21
- data/lib/active_record/associations/belongs_to_association.rb +15 -5
- data/lib/active_record/associations/builder/association.rb +16 -5
- data/lib/active_record/associations/builder/belongs_to.rb +7 -29
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +2 -11
- data/lib/active_record/associations/builder/has_one.rb +2 -2
- data/lib/active_record/associations/builder/singular_association.rb +8 -1
- data/lib/active_record/associations/collection_association.rb +32 -44
- data/lib/active_record/associations/collection_proxy.rb +1 -10
- data/lib/active_record/associations/has_many_association.rb +60 -14
- data/lib/active_record/associations/has_many_through_association.rb +34 -23
- data/lib/active_record/associations/has_one_association.rb +0 -1
- data/lib/active_record/associations/join_dependency.rb +7 -9
- data/lib/active_record/associations/join_dependency/join_association.rb +18 -14
- data/lib/active_record/associations/preloader.rb +2 -2
- data/lib/active_record/associations/preloader/association.rb +9 -5
- data/lib/active_record/associations/preloader/through_association.rb +3 -3
- data/lib/active_record/associations/singular_association.rb +16 -1
- data/lib/active_record/associations/through_association.rb +6 -22
- data/lib/active_record/attribute.rb +131 -0
- data/lib/active_record/attribute_assignment.rb +19 -11
- data/lib/active_record/attribute_decorators.rb +66 -0
- data/lib/active_record/attribute_methods.rb +53 -90
- data/lib/active_record/attribute_methods/before_type_cast.rb +2 -2
- data/lib/active_record/attribute_methods/dirty.rb +85 -42
- data/lib/active_record/attribute_methods/primary_key.rb +6 -8
- data/lib/active_record/attribute_methods/read.rb +14 -57
- data/lib/active_record/attribute_methods/serialization.rb +12 -146
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +32 -40
- data/lib/active_record/attribute_methods/write.rb +8 -23
- data/lib/active_record/attribute_set.rb +77 -0
- data/lib/active_record/attribute_set/builder.rb +32 -0
- data/lib/active_record/attributes.rb +122 -0
- data/lib/active_record/autosave_association.rb +11 -21
- data/lib/active_record/base.rb +9 -19
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +69 -45
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +22 -42
- data/lib/active_record/connection_adapters/abstract/quoting.rb +59 -60
- data/lib/active_record/connection_adapters/abstract/schema_creation.rb +37 -2
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +102 -21
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +9 -33
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +178 -55
- data/lib/active_record/connection_adapters/abstract/transaction.rb +120 -115
- data/lib/active_record/connection_adapters/abstract_adapter.rb +143 -57
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +156 -107
- data/lib/active_record/connection_adapters/column.rb +13 -244
- data/lib/active_record/connection_adapters/connection_specification.rb +6 -20
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +12 -15
- data/lib/active_record/connection_adapters/mysql_adapter.rb +55 -143
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +15 -27
- data/lib/active_record/connection_adapters/postgresql/column.rb +20 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +39 -20
- data/lib/active_record/connection_adapters/postgresql/oid.rb +29 -388
- data/lib/active_record/connection_adapters/postgresql/oid/array.rb +96 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit.rb +52 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bit_varying.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/bytea.rb +14 -0
- data/lib/active_record/connection_adapters/postgresql/oid/cidr.rb +46 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/date_time.rb +27 -0
- data/lib/active_record/connection_adapters/postgresql/oid/decimal.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/enum.rb +17 -0
- data/lib/active_record/connection_adapters/postgresql/oid/float.rb +21 -0
- data/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +59 -0
- data/lib/active_record/connection_adapters/postgresql/oid/inet.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/infinity.rb +13 -0
- data/lib/active_record/connection_adapters/postgresql/oid/integer.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/json.rb +35 -0
- data/lib/active_record/connection_adapters/postgresql/oid/jsonb.rb +23 -0
- data/lib/active_record/connection_adapters/postgresql/oid/money.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/point.rb +43 -0
- data/lib/active_record/connection_adapters/postgresql/oid/range.rb +76 -0
- data/lib/active_record/connection_adapters/postgresql/oid/specialized_string.rb +15 -0
- data/lib/active_record/connection_adapters/postgresql/oid/time.rb +11 -0
- data/lib/active_record/connection_adapters/postgresql/oid/type_map_initializer.rb +85 -0
- data/lib/active_record/connection_adapters/postgresql/oid/uuid.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/vector.rb +26 -0
- data/lib/active_record/connection_adapters/postgresql/oid/xml.rb +28 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +42 -122
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +4 -4
- data/lib/active_record/connection_adapters/postgresql/schema_definitions.rb +154 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +86 -34
- data/lib/active_record/connection_adapters/postgresql/utils.rb +66 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +188 -452
- data/lib/active_record/connection_adapters/schema_cache.rb +14 -28
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +54 -47
- data/lib/active_record/connection_handling.rb +1 -1
- data/lib/active_record/core.rb +119 -22
- data/lib/active_record/counter_cache.rb +60 -6
- data/lib/active_record/enum.rb +9 -10
- data/lib/active_record/errors.rb +27 -26
- data/lib/active_record/explain.rb +1 -1
- data/lib/active_record/fixtures.rb +52 -45
- data/lib/active_record/gem_version.rb +3 -3
- data/lib/active_record/inheritance.rb +33 -8
- data/lib/active_record/integration.rb +4 -4
- data/lib/active_record/locking/optimistic.rb +34 -16
- data/lib/active_record/migration.rb +22 -32
- data/lib/active_record/migration/command_recorder.rb +19 -2
- data/lib/active_record/migration/join_table.rb +1 -1
- data/lib/active_record/model_schema.rb +39 -48
- data/lib/active_record/nested_attributes.rb +8 -18
- data/lib/active_record/persistence.rb +39 -22
- data/lib/active_record/query_cache.rb +3 -3
- data/lib/active_record/querying.rb +1 -8
- data/lib/active_record/railtie.rb +17 -10
- data/lib/active_record/railties/databases.rake +47 -42
- data/lib/active_record/readonly_attributes.rb +0 -1
- data/lib/active_record/reflection.rb +225 -92
- data/lib/active_record/relation.rb +35 -11
- data/lib/active_record/relation/batches.rb +0 -2
- data/lib/active_record/relation/calculations.rb +28 -32
- data/lib/active_record/relation/delegation.rb +1 -1
- data/lib/active_record/relation/finder_methods.rb +42 -20
- data/lib/active_record/relation/merger.rb +0 -1
- data/lib/active_record/relation/predicate_builder.rb +1 -22
- data/lib/active_record/relation/predicate_builder/array_handler.rb +16 -11
- data/lib/active_record/relation/predicate_builder/relation_handler.rb +0 -4
- data/lib/active_record/relation/query_methods.rb +98 -62
- data/lib/active_record/relation/spawn_methods.rb +6 -7
- data/lib/active_record/result.rb +16 -9
- data/lib/active_record/sanitization.rb +8 -1
- data/lib/active_record/schema.rb +0 -1
- data/lib/active_record/schema_dumper.rb +51 -9
- data/lib/active_record/schema_migration.rb +4 -0
- data/lib/active_record/scoping/default.rb +5 -4
- data/lib/active_record/serializers/xml_serializer.rb +3 -7
- data/lib/active_record/statement_cache.rb +79 -5
- data/lib/active_record/store.rb +5 -5
- data/lib/active_record/tasks/database_tasks.rb +37 -5
- data/lib/active_record/tasks/mysql_database_tasks.rb +10 -16
- data/lib/active_record/tasks/postgresql_database_tasks.rb +2 -2
- data/lib/active_record/timestamp.rb +9 -7
- data/lib/active_record/transactions.rb +35 -21
- data/lib/active_record/type.rb +20 -0
- data/lib/active_record/type/binary.rb +40 -0
- data/lib/active_record/type/boolean.rb +19 -0
- data/lib/active_record/type/date.rb +46 -0
- data/lib/active_record/type/date_time.rb +43 -0
- data/lib/active_record/type/decimal.rb +40 -0
- data/lib/active_record/type/decimal_without_scale.rb +11 -0
- data/lib/active_record/type/float.rb +19 -0
- data/lib/active_record/type/hash_lookup_type_map.rb +19 -0
- data/lib/active_record/type/integer.rb +23 -0
- data/lib/active_record/type/mutable.rb +16 -0
- data/lib/active_record/type/numeric.rb +36 -0
- data/lib/active_record/type/serialized.rb +51 -0
- data/lib/active_record/type/string.rb +36 -0
- data/lib/active_record/type/text.rb +11 -0
- data/lib/active_record/type/time.rb +26 -0
- data/lib/active_record/type/time_value.rb +38 -0
- data/lib/active_record/type/type_map.rb +48 -0
- data/lib/active_record/type/value.rb +101 -0
- data/lib/active_record/validations.rb +21 -16
- data/lib/active_record/validations/uniqueness.rb +9 -23
- data/lib/rails/generators/active_record/migration/migration_generator.rb +8 -4
- data/lib/rails/generators/active_record/migration/templates/create_table_migration.rb +1 -1
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -1
- metadata +71 -14
- data/lib/active_record/connection_adapters/postgresql/cast.rb +0 -168
data/README.rdoc
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
= Active Record -- Object-relational mapping
|
1
|
+
= Active Record -- Object-relational mapping in Rails
|
2
2
|
|
3
3
|
Active Record connects classes to relational database tables to establish an
|
4
4
|
almost zero-configuration persistence layer for applications. The library
|
@@ -20,8 +20,10 @@ A short rundown of some of the major features:
|
|
20
20
|
class Product < ActiveRecord::Base
|
21
21
|
end
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
{Learn more}[link:classes/ActiveRecord/Base.html]
|
24
|
+
|
25
|
+
The Product class is automatically mapped to the table named "products",
|
26
|
+
which might look like this:
|
25
27
|
|
26
28
|
CREATE TABLE products (
|
27
29
|
id int(11) NOT NULL auto_increment,
|
@@ -29,10 +31,8 @@ A short rundown of some of the major features:
|
|
29
31
|
PRIMARY KEY (id)
|
30
32
|
);
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
{Learn more}[link:classes/ActiveRecord/Base.html]
|
34
|
+
This would also define the following accessors: `Product#name` and
|
35
|
+
`Product#name=(new_name)`.
|
36
36
|
|
37
37
|
|
38
38
|
* Associations between objects defined by simple class methods.
|
@@ -130,7 +130,7 @@ A short rundown of some of the major features:
|
|
130
130
|
SQLite3[link:classes/ActiveRecord/ConnectionAdapters/SQLite3Adapter.html].
|
131
131
|
|
132
132
|
|
133
|
-
* Logging support for Log4r[
|
133
|
+
* Logging support for Log4r[https://github.com/colbygk/log4r] and Logger[http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc].
|
134
134
|
|
135
135
|
ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
|
136
136
|
ActiveRecord::Base.logger = Log4r::Logger.new('Application Log')
|
@@ -192,7 +192,7 @@ The latest version of Active Record can be installed with RubyGems:
|
|
192
192
|
|
193
193
|
Source code can be downloaded as part of the Rails project on GitHub:
|
194
194
|
|
195
|
-
* https://github.com/rails/rails/tree/
|
195
|
+
* https://github.com/rails/rails/tree/master/activerecord
|
196
196
|
|
197
197
|
|
198
198
|
== License
|
@@ -208,6 +208,11 @@ API documentation is at:
|
|
208
208
|
|
209
209
|
* http://api.rubyonrails.org
|
210
210
|
|
211
|
-
Bug reports
|
211
|
+
Bug reports can be filed for the Ruby on Rails project here:
|
212
212
|
|
213
213
|
* https://github.com/rails/rails/issues
|
214
|
+
|
215
|
+
Feature requests should be discussed on the rails-core mailing list here:
|
216
|
+
|
217
|
+
* https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
|
218
|
+
|
data/lib/active_record.rb
CHANGED
@@ -27,10 +27,12 @@ require 'active_model'
|
|
27
27
|
require 'arel'
|
28
28
|
|
29
29
|
require 'active_record/version'
|
30
|
+
require 'active_record/attribute_set'
|
30
31
|
|
31
32
|
module ActiveRecord
|
32
33
|
extend ActiveSupport::Autoload
|
33
34
|
|
35
|
+
autoload :Attribute
|
34
36
|
autoload :Base
|
35
37
|
autoload :Callbacks
|
36
38
|
autoload :Core
|
@@ -50,7 +52,6 @@ module ActiveRecord
|
|
50
52
|
autoload :QueryCache
|
51
53
|
autoload :Querying
|
52
54
|
autoload :ReadonlyAttributes
|
53
|
-
autoload :RecordInvalid, 'active_record/validations'
|
54
55
|
autoload :Reflection
|
55
56
|
autoload :RuntimeRegistry
|
56
57
|
autoload :Sanitization
|
@@ -129,10 +129,10 @@ module ActiveRecord
|
|
129
129
|
# is an instance of the value class. Specifying a custom converter allows the new value to be automatically
|
130
130
|
# converted to an instance of value class if necessary.
|
131
131
|
#
|
132
|
-
# For example, the NetworkResource model has +network_address+ and +cidr_range+ attributes that
|
133
|
-
#
|
134
|
-
# for the value class is called +create+ and it expects a CIDR address string as a parameter.
|
135
|
-
# values can be assigned to the value object using either another NetAddr::CIDR object, a string
|
132
|
+
# For example, the NetworkResource model has +network_address+ and +cidr_range+ attributes that should be
|
133
|
+
# aggregated using the NetAddr::CIDR value class (http://www.ruby-doc.org/gems/docs/n/netaddr-1.5.0/NetAddr/CIDR.html).
|
134
|
+
# The constructor for the value class is called +create+ and it expects a CIDR address string as a parameter.
|
135
|
+
# New values can be assigned to the value object using either another NetAddr::CIDR object, a string
|
136
136
|
# or an array. The <tt>:constructor</tt> and <tt>:converter</tt> options can be used to meet
|
137
137
|
# these requirements:
|
138
138
|
#
|
@@ -230,8 +230,8 @@ module ActiveRecord
|
|
230
230
|
private
|
231
231
|
def reader_method(name, class_name, mapping, allow_nil, constructor)
|
232
232
|
define_method(name) do
|
233
|
-
if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? {|
|
234
|
-
attrs = mapping.collect {|
|
233
|
+
if @aggregation_cache[name].nil? && (!allow_nil || mapping.any? {|key, _| !read_attribute(key).nil? })
|
234
|
+
attrs = mapping.collect {|key, _| read_attribute(key)}
|
235
235
|
object = constructor.respond_to?(:call) ?
|
236
236
|
constructor.call(*attrs) :
|
237
237
|
class_name.constantize.send(constructor, *attrs)
|
@@ -244,15 +244,19 @@ module ActiveRecord
|
|
244
244
|
def writer_method(name, class_name, mapping, allow_nil, converter)
|
245
245
|
define_method("#{name}=") do |part|
|
246
246
|
klass = class_name.constantize
|
247
|
+
if part.is_a?(Hash)
|
248
|
+
part = klass.new(*part.values)
|
249
|
+
end
|
250
|
+
|
247
251
|
unless part.is_a?(klass) || converter.nil? || part.nil?
|
248
252
|
part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part)
|
249
253
|
end
|
250
254
|
|
251
255
|
if part.nil? && allow_nil
|
252
|
-
mapping.each { |
|
256
|
+
mapping.each { |key, _| self[key] = nil }
|
253
257
|
@aggregation_cache[name] = nil
|
254
258
|
else
|
255
|
-
mapping.each { |
|
259
|
+
mapping.each { |key, value| self[key] = part.send(value) }
|
256
260
|
@aggregation_cache[name] = part.freeze
|
257
261
|
end
|
258
262
|
end
|
@@ -202,12 +202,13 @@ module ActiveRecord
|
|
202
202
|
# For instance, +attributes+ and +connection+ would be bad choices for association names.
|
203
203
|
#
|
204
204
|
# == Auto-generated methods
|
205
|
+
# See also Instance Public methods below for more details.
|
205
206
|
#
|
206
207
|
# === Singular associations (one-to-one)
|
207
208
|
# | | belongs_to |
|
208
209
|
# generated methods | belongs_to | :polymorphic | has_one
|
209
210
|
# ----------------------------------+------------+--------------+---------
|
210
|
-
# other
|
211
|
+
# other(force_reload=false) | X | X | X
|
211
212
|
# other=(other) | X | X | X
|
212
213
|
# build_other(attributes={}) | X | | X
|
213
214
|
# create_other(attributes={}) | X | | X
|
@@ -217,7 +218,7 @@ module ActiveRecord
|
|
217
218
|
# | | | has_many
|
218
219
|
# generated methods | habtm | has_many | :through
|
219
220
|
# ----------------------------------+-------+----------+----------
|
220
|
-
# others
|
221
|
+
# others(force_reload=false) | X | X | X
|
221
222
|
# others=(other,other,...) | X | X | X
|
222
223
|
# other_ids | X | X | X
|
223
224
|
# other_ids=(id,id,...) | X | X | X
|
@@ -419,6 +420,10 @@ module ActiveRecord
|
|
419
420
|
# has_many :birthday_events, ->(user) { where starts_on: user.birthday }, class_name: 'Event'
|
420
421
|
# end
|
421
422
|
#
|
423
|
+
# Note: Joining, eager loading and preloading of these associations is not fully possible.
|
424
|
+
# These operations happen before instance creation and the scope will be called with a +nil+ argument.
|
425
|
+
# This can lead to unexpected behavior and is deprecated.
|
426
|
+
#
|
422
427
|
# == Association callbacks
|
423
428
|
#
|
424
429
|
# Similar to the normal callbacks that hook into the life cycle of an Active Record object,
|
@@ -536,8 +541,8 @@ module ActiveRecord
|
|
536
541
|
# end
|
537
542
|
#
|
538
543
|
# @firm = Firm.first
|
539
|
-
# @firm.clients.
|
540
|
-
# @firm.invoices
|
544
|
+
# @firm.clients.flat_map { |c| c.invoices } # select all invoices for all clients of the firm
|
545
|
+
# @firm.invoices # selects all invoices by going through the Client join model
|
541
546
|
#
|
542
547
|
# Similarly you can go through a +has_one+ association on the join model:
|
543
548
|
#
|
@@ -712,9 +717,9 @@ module ActiveRecord
|
|
712
717
|
# == Eager loading of associations
|
713
718
|
#
|
714
719
|
# Eager loading is a way to find objects of a certain class and a number of named associations.
|
715
|
-
# This is one of the easiest ways of to prevent the dreaded 1
|
720
|
+
# This is one of the easiest ways of to prevent the dreaded N+1 problem in which fetching 100
|
716
721
|
# posts that each need to display their author triggers 101 database queries. Through the
|
717
|
-
# use of eager loading, the
|
722
|
+
# use of eager loading, the number of queries will be reduced from 101 to 2.
|
718
723
|
#
|
719
724
|
# class Post < ActiveRecord::Base
|
720
725
|
# belongs_to :author
|
@@ -774,16 +779,15 @@ module ActiveRecord
|
|
774
779
|
# In the above example posts with no approved comments are not returned at all, because
|
775
780
|
# the conditions apply to the SQL statement as a whole and not just to the association.
|
776
781
|
#
|
782
|
+
# You must disambiguate column references for this fallback to happen, for example
|
783
|
+
# <tt>order: "author.name DESC"</tt> will work but <tt>order: "name DESC"</tt> will not.
|
784
|
+
#
|
777
785
|
# If you want to load all posts (including posts with no approved comments) then write
|
778
786
|
# your own LEFT OUTER JOIN query using ON
|
779
787
|
#
|
780
|
-
# Post.joins(
|
788
|
+
# Post.joins("LEFT OUTER JOIN comments ON comments.post_id = posts.id AND comments.approved = '1'")
|
781
789
|
#
|
782
|
-
#
|
783
|
-
# <tt>order: "author.name DESC"</tt> will work but <tt>order: "name DESC"</tt> will not.
|
784
|
-
#
|
785
|
-
# If you do want eager load only some members of an association it is usually more natural
|
786
|
-
# to include an association which has conditions defined on it:
|
790
|
+
# In this case it is usually more natural to include an association which has conditions defined on it:
|
787
791
|
#
|
788
792
|
# class Post < ActiveRecord::Base
|
789
793
|
# has_many :approved_comments, -> { where approved: true }, class_name: 'Comment'
|
@@ -1048,6 +1052,9 @@ module ActiveRecord
|
|
1048
1052
|
# Specifies a one-to-many association. The following methods for retrieval and query of
|
1049
1053
|
# collections of associated objects will be added:
|
1050
1054
|
#
|
1055
|
+
# +collection+ is a placeholder for the symbol passed as the +name+ argument, so
|
1056
|
+
# <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.
|
1057
|
+
#
|
1051
1058
|
# [collection(force_reload = false)]
|
1052
1059
|
# Returns an array of all the associated objects.
|
1053
1060
|
# An empty array is returned if none are found.
|
@@ -1106,9 +1113,6 @@ module ActiveRecord
|
|
1106
1113
|
# Does the same as <tt>collection.create</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt>
|
1107
1114
|
# if the record is invalid.
|
1108
1115
|
#
|
1109
|
-
# (*Note*: +collection+ is replaced with the symbol passed as the first argument, so
|
1110
|
-
# <tt>has_many :clients</tt> would add among others <tt>clients.empty?</tt>.)
|
1111
|
-
#
|
1112
1116
|
# === Example
|
1113
1117
|
#
|
1114
1118
|
# A <tt>Firm</tt> class declares <tt>has_many :clients</tt>, which will add:
|
@@ -1127,7 +1131,7 @@ module ActiveRecord
|
|
1127
1131
|
# * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
|
1128
1132
|
# * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
|
1129
1133
|
# * <tt>Firm#clients.create!</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save!</tt>)
|
1130
|
-
# The declaration can also include an options hash to specialize the behavior of the association.
|
1134
|
+
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
1131
1135
|
#
|
1132
1136
|
# === Options
|
1133
1137
|
# [:class_name]
|
@@ -1205,7 +1209,7 @@ module ActiveRecord
|
|
1205
1209
|
# Option examples:
|
1206
1210
|
# has_many :comments, -> { order "posted_on" }
|
1207
1211
|
# has_many :comments, -> { includes :author }
|
1208
|
-
# has_many :people, -> { where(
|
1212
|
+
# has_many :people, -> { where(deleted: false).order("name") }, class_name: "Person"
|
1209
1213
|
# has_many :tracks, -> { order "position" }, dependent: :destroy
|
1210
1214
|
# has_many :comments, dependent: :nullify
|
1211
1215
|
# has_many :tags, as: :taggable
|
@@ -1223,6 +1227,9 @@ module ActiveRecord
|
|
1223
1227
|
#
|
1224
1228
|
# The following methods for retrieval and query of a single associated object will be added:
|
1225
1229
|
#
|
1230
|
+
# +association+ is a placeholder for the symbol passed as the +name+ argument, so
|
1231
|
+
# <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.
|
1232
|
+
#
|
1226
1233
|
# [association(force_reload = false)]
|
1227
1234
|
# Returns the associated object. +nil+ is returned if none is found.
|
1228
1235
|
# [association=(associate)]
|
@@ -1241,9 +1248,6 @@ module ActiveRecord
|
|
1241
1248
|
# Does the same as <tt>create_association</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt>
|
1242
1249
|
# if the record is invalid.
|
1243
1250
|
#
|
1244
|
-
# (+association+ is replaced with the symbol passed as the first argument, so
|
1245
|
-
# <tt>has_one :manager</tt> would add among others <tt>manager.nil?</tt>.)
|
1246
|
-
#
|
1247
1251
|
# === Example
|
1248
1252
|
#
|
1249
1253
|
# An Account class declares <tt>has_one :beneficiary</tt>, which will add:
|
@@ -1255,7 +1259,7 @@ module ActiveRecord
|
|
1255
1259
|
#
|
1256
1260
|
# === Options
|
1257
1261
|
#
|
1258
|
-
# The declaration can also include an options hash to specialize the behavior of the association.
|
1262
|
+
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
1259
1263
|
#
|
1260
1264
|
# Options are:
|
1261
1265
|
# [:class_name]
|
@@ -1305,6 +1309,10 @@ module ActiveRecord
|
|
1305
1309
|
# that is the inverse of this <tt>has_one</tt> association. Does not work in combination
|
1306
1310
|
# with <tt>:through</tt> or <tt>:as</tt> options.
|
1307
1311
|
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
|
1312
|
+
# [:required]
|
1313
|
+
# When set to +true+, the association will also have its presence validated.
|
1314
|
+
# This will validate the association itself, not the id. You can use
|
1315
|
+
# +:inverse_of+ to avoid an extra query during validation.
|
1308
1316
|
#
|
1309
1317
|
# Option examples:
|
1310
1318
|
# has_one :credit_card, dependent: :destroy # destroys the associated credit card
|
@@ -1316,6 +1324,7 @@ module ActiveRecord
|
|
1316
1324
|
# has_one :boss, readonly: :true
|
1317
1325
|
# has_one :club, through: :membership
|
1318
1326
|
# has_one :primary_address, -> { where primary: true }, through: :addressables, source: :addressable
|
1327
|
+
# has_one :credit_card, required: true
|
1319
1328
|
def has_one(name, scope = nil, options = {})
|
1320
1329
|
reflection = Builder::HasOne.build(self, name, scope, options)
|
1321
1330
|
Reflection.add_reflection self, name, reflection
|
@@ -1329,6 +1338,9 @@ module ActiveRecord
|
|
1329
1338
|
# Methods will be added for retrieval and query for a single associated object, for which
|
1330
1339
|
# this object holds an id:
|
1331
1340
|
#
|
1341
|
+
# +association+ is a placeholder for the symbol passed as the +name+ argument, so
|
1342
|
+
# <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.
|
1343
|
+
#
|
1332
1344
|
# [association(force_reload = false)]
|
1333
1345
|
# Returns the associated object. +nil+ is returned if none is found.
|
1334
1346
|
# [association=(associate)]
|
@@ -1344,9 +1356,6 @@ module ActiveRecord
|
|
1344
1356
|
# Does the same as <tt>create_association</tt>, but raises <tt>ActiveRecord::RecordInvalid</tt>
|
1345
1357
|
# if the record is invalid.
|
1346
1358
|
#
|
1347
|
-
# (+association+ is replaced with the symbol passed as the first argument, so
|
1348
|
-
# <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.)
|
1349
|
-
#
|
1350
1359
|
# === Example
|
1351
1360
|
#
|
1352
1361
|
# A Post class declares <tt>belongs_to :author</tt>, which will add:
|
@@ -1355,7 +1364,18 @@ module ActiveRecord
|
|
1355
1364
|
# * <tt>Post#build_author</tt> (similar to <tt>post.author = Author.new</tt>)
|
1356
1365
|
# * <tt>Post#create_author</tt> (similar to <tt>post.author = Author.new; post.author.save; post.author</tt>)
|
1357
1366
|
# * <tt>Post#create_author!</tt> (similar to <tt>post.author = Author.new; post.author.save!; post.author</tt>)
|
1358
|
-
# The declaration can also include an options hash to specialize the behavior of the association.
|
1367
|
+
# The declaration can also include an +options+ hash to specialize the behavior of the association.
|
1368
|
+
#
|
1369
|
+
# === Scopes
|
1370
|
+
#
|
1371
|
+
# You can pass a second argument +scope+ as a callable (i.e. proc or
|
1372
|
+
# lambda) to retrieve a specific record or customize the generated query
|
1373
|
+
# when you access the associated object.
|
1374
|
+
#
|
1375
|
+
# Scope examples:
|
1376
|
+
# belongs_to :user, -> { where(id: 2) }
|
1377
|
+
# belongs_to :user, -> { joins(:friends) }
|
1378
|
+
# belongs_to :level, ->(level) { where("game_level > ?", level.current) }
|
1359
1379
|
#
|
1360
1380
|
# === Options
|
1361
1381
|
#
|
@@ -1409,7 +1429,7 @@ module ActiveRecord
|
|
1409
1429
|
#
|
1410
1430
|
# Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
|
1411
1431
|
# [:touch]
|
1412
|
-
# If true, the associated object will be touched (the updated_at/on attributes set to
|
1432
|
+
# If true, the associated object will be touched (the updated_at/on attributes set to current time)
|
1413
1433
|
# when this record is either saved or destroyed. If you specify a symbol, that attribute
|
1414
1434
|
# will be updated with the current time in addition to the updated_at/on attribute.
|
1415
1435
|
# [:inverse_of]
|
@@ -1417,6 +1437,10 @@ module ActiveRecord
|
|
1417
1437
|
# object that is the inverse of this <tt>belongs_to</tt> association. Does not work in
|
1418
1438
|
# combination with the <tt>:polymorphic</tt> options.
|
1419
1439
|
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
|
1440
|
+
# [:required]
|
1441
|
+
# When set to +true+, the association will also have its presence validated.
|
1442
|
+
# This will validate the association itself, not the id. You can use
|
1443
|
+
# +:inverse_of+ to avoid an extra query during validation.
|
1420
1444
|
#
|
1421
1445
|
# Option examples:
|
1422
1446
|
# belongs_to :firm, foreign_key: "client_of"
|
@@ -1429,6 +1453,7 @@ module ActiveRecord
|
|
1429
1453
|
# belongs_to :post, counter_cache: true
|
1430
1454
|
# belongs_to :company, touch: true
|
1431
1455
|
# belongs_to :company, touch: :employees_last_updated_at
|
1456
|
+
# belongs_to :company, required: true
|
1432
1457
|
def belongs_to(name, scope = nil, options = {})
|
1433
1458
|
reflection = Builder::BelongsTo.build(self, name, scope, options)
|
1434
1459
|
Reflection.add_reflection self, name, reflection
|
@@ -1466,6 +1491,9 @@ module ActiveRecord
|
|
1466
1491
|
#
|
1467
1492
|
# Adds the following methods for retrieval and query:
|
1468
1493
|
#
|
1494
|
+
# +collection+ is a placeholder for the symbol passed as the +name+ argument, so
|
1495
|
+
# <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.
|
1496
|
+
#
|
1469
1497
|
# [collection(force_reload = false)]
|
1470
1498
|
# Returns an array of all the associated objects.
|
1471
1499
|
# An empty array is returned if none are found.
|
@@ -1507,9 +1535,6 @@ module ActiveRecord
|
|
1507
1535
|
# with +attributes+, linked to this object through the join table, and that has already been
|
1508
1536
|
# saved (if it passed the validation).
|
1509
1537
|
#
|
1510
|
-
# (+collection+ is replaced with the symbol passed as the first argument, so
|
1511
|
-
# <tt>has_and_belongs_to_many :categories</tt> would add among others <tt>categories.empty?</tt>.)
|
1512
|
-
#
|
1513
1538
|
# === Example
|
1514
1539
|
#
|
1515
1540
|
# A Developer class declares <tt>has_and_belongs_to_many :projects</tt>, which will add:
|
@@ -1527,7 +1552,7 @@ module ActiveRecord
|
|
1527
1552
|
# * <tt>Developer#projects.exists?(...)</tt>
|
1528
1553
|
# * <tt>Developer#projects.build</tt> (similar to <tt>Project.new("developer_id" => id)</tt>)
|
1529
1554
|
# * <tt>Developer#projects.create</tt> (similar to <tt>c = Project.new("developer_id" => id); c.save; c</tt>)
|
1530
|
-
# The declaration may include an options hash to specialize the behavior of the association.
|
1555
|
+
# The declaration may include an +options+ hash to specialize the behavior of the association.
|
1531
1556
|
#
|
1532
1557
|
# === Options
|
1533
1558
|
#
|
@@ -1573,7 +1598,7 @@ module ActiveRecord
|
|
1573
1598
|
scope = nil
|
1574
1599
|
end
|
1575
1600
|
|
1576
|
-
habtm_reflection = ActiveRecord::Reflection::
|
1601
|
+
habtm_reflection = ActiveRecord::Reflection::HasAndBelongsToManyReflection.new(name, scope, options, self)
|
1577
1602
|
|
1578
1603
|
builder = Builder::HasAndBelongsToMany.new name, self, options
|
1579
1604
|
|
@@ -1588,7 +1613,7 @@ module ActiveRecord
|
|
1588
1613
|
|
1589
1614
|
Builder::HasMany.define_callbacks self, middle_reflection
|
1590
1615
|
Reflection.add_reflection self, middle_reflection.name, middle_reflection
|
1591
|
-
middle_reflection.parent_reflection = [name.
|
1616
|
+
middle_reflection.parent_reflection = [name.to_s, habtm_reflection]
|
1592
1617
|
|
1593
1618
|
include Module.new {
|
1594
1619
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
@@ -1609,7 +1634,7 @@ module ActiveRecord
|
|
1609
1634
|
end
|
1610
1635
|
|
1611
1636
|
has_many name, scope, hm_options, &extension
|
1612
|
-
self._reflections[name.
|
1637
|
+
self._reflections[name.to_s].parent_reflection = [name.to_s, habtm_reflection]
|
1613
1638
|
end
|
1614
1639
|
end
|
1615
1640
|
end
|
@@ -179,7 +179,7 @@ module ActiveRecord
|
|
179
179
|
def creation_attributes
|
180
180
|
attributes = {}
|
181
181
|
|
182
|
-
if (reflection.
|
182
|
+
if (reflection.has_one? || reflection.collection?) && !options[:through]
|
183
183
|
attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
|
184
184
|
|
185
185
|
if reflection.options[:as]
|
@@ -1,12 +1,34 @@
|
|
1
1
|
module ActiveRecord
|
2
2
|
module Associations
|
3
3
|
class AssociationScope #:nodoc:
|
4
|
-
INSTANCE = new
|
5
|
-
|
6
4
|
def self.scope(association, connection)
|
7
5
|
INSTANCE.scope association, connection
|
8
6
|
end
|
9
7
|
|
8
|
+
class BindSubstitution
|
9
|
+
def initialize(block)
|
10
|
+
@block = block
|
11
|
+
end
|
12
|
+
|
13
|
+
def bind_value(scope, column, value, alias_tracker)
|
14
|
+
substitute = alias_tracker.connection.substitute_at(
|
15
|
+
column, scope.bind_values.length)
|
16
|
+
scope.bind_values += [[column, @block.call(value)]]
|
17
|
+
substitute
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.create(&block)
|
22
|
+
block = block ? block : lambda { |val| val }
|
23
|
+
new BindSubstitution.new(block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(bind_substitution)
|
27
|
+
@bind_substitution = bind_substitution
|
28
|
+
end
|
29
|
+
|
30
|
+
INSTANCE = create
|
31
|
+
|
10
32
|
def scope(association, connection)
|
11
33
|
klass = association.klass
|
12
34
|
reflection = association.reflection
|
@@ -22,6 +44,23 @@ module ActiveRecord
|
|
22
44
|
Arel::Nodes::InnerJoin
|
23
45
|
end
|
24
46
|
|
47
|
+
def self.get_bind_values(owner, chain)
|
48
|
+
bvs = []
|
49
|
+
chain.each_with_index do |reflection, i|
|
50
|
+
if reflection == chain.last
|
51
|
+
bvs << reflection.join_id_for(owner)
|
52
|
+
if reflection.type
|
53
|
+
bvs << owner.class.base_class.name
|
54
|
+
end
|
55
|
+
else
|
56
|
+
if reflection.type
|
57
|
+
bvs << chain[i + 1].klass.base_class.name
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
bvs
|
62
|
+
end
|
63
|
+
|
25
64
|
private
|
26
65
|
|
27
66
|
def construct_tables(chain, klass, refl, alias_tracker)
|
@@ -49,10 +88,7 @@ module ActiveRecord
|
|
49
88
|
end
|
50
89
|
|
51
90
|
def bind_value(scope, column, value, alias_tracker)
|
52
|
-
|
53
|
-
column, scope.bind_values.length)
|
54
|
-
scope.bind_values += [[column, value]]
|
55
|
-
substitute
|
91
|
+
@bind_substitution.bind_value scope, column, value, alias_tracker
|
56
92
|
end
|
57
93
|
|
58
94
|
def bind(scope, table_name, column_name, value, tracker)
|
@@ -69,18 +105,9 @@ module ActiveRecord
|
|
69
105
|
chain.each_with_index do |reflection, i|
|
70
106
|
table, foreign_table = tables.shift, tables.first
|
71
107
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
else
|
76
|
-
key = reflection.association_primary_key
|
77
|
-
end
|
78
|
-
|
79
|
-
foreign_key = reflection.foreign_key
|
80
|
-
else
|
81
|
-
key = reflection.foreign_key
|
82
|
-
foreign_key = reflection.active_record_primary_key
|
83
|
-
end
|
108
|
+
join_keys = reflection.join_keys(assoc_klass)
|
109
|
+
key = join_keys.key
|
110
|
+
foreign_key = join_keys.foreign_key
|
84
111
|
|
85
112
|
if reflection == chain.last
|
86
113
|
bind_val = bind scope, table.table_name, key.to_s, owner[foreign_key], tracker
|
@@ -88,7 +115,7 @@ module ActiveRecord
|
|
88
115
|
|
89
116
|
if reflection.type
|
90
117
|
value = owner.class.base_class.name
|
91
|
-
bind_val = bind scope, table.table_name, reflection.type
|
118
|
+
bind_val = bind scope, table.table_name, reflection.type, value, tracker
|
92
119
|
scope = scope.where(table[reflection.type].eq(bind_val))
|
93
120
|
end
|
94
121
|
else
|
@@ -96,7 +123,7 @@ module ActiveRecord
|
|
96
123
|
|
97
124
|
if reflection.type
|
98
125
|
value = chain[i + 1].klass.base_class.name
|
99
|
-
bind_val = bind scope, table.table_name, reflection.type
|
126
|
+
bind_val = bind scope, table.table_name, reflection.type, value, tracker
|
100
127
|
scope = scope.where(table[reflection.type].eq(bind_val))
|
101
128
|
end
|
102
129
|
|
@@ -120,6 +147,7 @@ module ActiveRecord
|
|
120
147
|
end
|
121
148
|
|
122
149
|
scope.where_values += item.where_values
|
150
|
+
scope.bind_values += item.bind_values
|
123
151
|
scope.order_values |= item.order_values
|
124
152
|
end
|
125
153
|
end
|
@@ -143,7 +171,11 @@ module ActiveRecord
|
|
143
171
|
end
|
144
172
|
|
145
173
|
def eval_scope(klass, scope, owner)
|
146
|
-
|
174
|
+
if scope.is_a?(Relation)
|
175
|
+
scope
|
176
|
+
else
|
177
|
+
klass.unscoped.instance_exec(owner, &scope)
|
178
|
+
end
|
147
179
|
end
|
148
180
|
end
|
149
181
|
end
|