activerecord 3.2.22.5 → 4.0.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 +1024 -543
- data/MIT-LICENSE +1 -1
- data/README.rdoc +20 -29
- data/examples/performance.rb +1 -1
- data/lib/active_record.rb +55 -44
- data/lib/active_record/aggregations.rb +40 -34
- data/lib/active_record/associations.rb +204 -276
- data/lib/active_record/associations/alias_tracker.rb +1 -1
- data/lib/active_record/associations/association.rb +30 -35
- data/lib/active_record/associations/association_scope.rb +40 -40
- data/lib/active_record/associations/belongs_to_association.rb +15 -2
- data/lib/active_record/associations/builder/association.rb +81 -28
- data/lib/active_record/associations/builder/belongs_to.rb +35 -57
- data/lib/active_record/associations/builder/collection_association.rb +54 -40
- data/lib/active_record/associations/builder/has_and_belongs_to_many.rb +23 -41
- data/lib/active_record/associations/builder/has_many.rb +8 -64
- data/lib/active_record/associations/builder/has_one.rb +13 -50
- data/lib/active_record/associations/builder/singular_association.rb +13 -13
- data/lib/active_record/associations/collection_association.rb +92 -88
- data/lib/active_record/associations/collection_proxy.rb +913 -63
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +12 -10
- data/lib/active_record/associations/has_many_association.rb +35 -9
- data/lib/active_record/associations/has_many_through_association.rb +24 -14
- data/lib/active_record/associations/has_one_association.rb +33 -13
- data/lib/active_record/associations/has_one_through_association.rb +1 -1
- data/lib/active_record/associations/join_dependency.rb +2 -2
- data/lib/active_record/associations/join_dependency/join_association.rb +17 -22
- data/lib/active_record/associations/join_dependency/join_part.rb +1 -1
- data/lib/active_record/associations/join_helper.rb +1 -11
- data/lib/active_record/associations/preloader.rb +14 -17
- data/lib/active_record/associations/preloader/association.rb +29 -33
- data/lib/active_record/associations/preloader/collection_association.rb +1 -1
- data/lib/active_record/associations/preloader/has_and_belongs_to_many.rb +1 -1
- data/lib/active_record/associations/preloader/has_many_through.rb +1 -1
- data/lib/active_record/associations/preloader/has_one.rb +1 -1
- data/lib/active_record/associations/preloader/through_association.rb +13 -17
- data/lib/active_record/associations/singular_association.rb +11 -11
- data/lib/active_record/associations/through_association.rb +2 -2
- data/lib/active_record/attribute_assignment.rb +133 -153
- data/lib/active_record/attribute_methods.rb +196 -93
- data/lib/active_record/attribute_methods/before_type_cast.rb +44 -5
- data/lib/active_record/attribute_methods/dirty.rb +31 -28
- data/lib/active_record/attribute_methods/primary_key.rb +38 -30
- data/lib/active_record/attribute_methods/query.rb +5 -4
- data/lib/active_record/attribute_methods/read.rb +62 -91
- data/lib/active_record/attribute_methods/serialization.rb +97 -66
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +39 -45
- data/lib/active_record/attribute_methods/write.rb +32 -39
- data/lib/active_record/autosave_association.rb +56 -70
- data/lib/active_record/base.rb +53 -450
- data/lib/active_record/callbacks.rb +53 -18
- data/lib/active_record/coders/yaml_column.rb +11 -9
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +353 -197
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +9 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +130 -131
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +24 -19
- data/lib/active_record/connection_adapters/abstract/quoting.rb +23 -3
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +101 -91
- data/lib/active_record/connection_adapters/abstract/schema_dumper.rb +59 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +225 -96
- data/lib/active_record/connection_adapters/abstract/transaction.rb +203 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +99 -46
- data/lib/active_record/connection_adapters/abstract_mysql_adapter.rb +114 -36
- data/lib/active_record/connection_adapters/column.rb +46 -24
- data/lib/active_record/connection_adapters/connection_specification.rb +96 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +16 -32
- data/lib/active_record/connection_adapters/mysql_adapter.rb +181 -64
- data/lib/active_record/connection_adapters/postgresql/array_parser.rb +97 -0
- data/lib/active_record/connection_adapters/postgresql/cast.rb +132 -0
- data/lib/active_record/connection_adapters/postgresql/database_statements.rb +242 -0
- data/lib/active_record/connection_adapters/postgresql/oid.rb +347 -0
- data/lib/active_record/connection_adapters/postgresql/quoting.rb +158 -0
- data/lib/active_record/connection_adapters/postgresql/referential_integrity.rb +30 -0
- data/lib/active_record/connection_adapters/postgresql/schema_statements.rb +448 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +454 -885
- data/lib/active_record/connection_adapters/schema_cache.rb +48 -16
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +574 -13
- data/lib/active_record/connection_handling.rb +98 -0
- data/lib/active_record/core.rb +428 -0
- data/lib/active_record/counter_cache.rb +106 -108
- data/lib/active_record/dynamic_matchers.rb +110 -63
- data/lib/active_record/errors.rb +25 -8
- data/lib/active_record/explain.rb +8 -58
- data/lib/active_record/explain_subscriber.rb +6 -3
- data/lib/active_record/fixture_set/file.rb +56 -0
- data/lib/active_record/fixtures.rb +146 -148
- data/lib/active_record/inheritance.rb +77 -59
- data/lib/active_record/integration.rb +5 -5
- data/lib/active_record/locale/en.yml +8 -1
- data/lib/active_record/locking/optimistic.rb +38 -42
- data/lib/active_record/locking/pessimistic.rb +4 -4
- data/lib/active_record/log_subscriber.rb +19 -9
- data/lib/active_record/migration.rb +318 -153
- data/lib/active_record/migration/command_recorder.rb +90 -31
- data/lib/active_record/migration/join_table.rb +15 -0
- data/lib/active_record/model_schema.rb +69 -92
- data/lib/active_record/nested_attributes.rb +113 -148
- data/lib/active_record/null_relation.rb +65 -0
- data/lib/active_record/persistence.rb +188 -97
- data/lib/active_record/query_cache.rb +18 -36
- data/lib/active_record/querying.rb +19 -15
- data/lib/active_record/railtie.rb +91 -36
- data/lib/active_record/railties/console_sandbox.rb +0 -2
- data/lib/active_record/railties/controller_runtime.rb +2 -2
- data/lib/active_record/railties/databases.rake +90 -309
- data/lib/active_record/railties/jdbcmysql_error.rb +1 -1
- data/lib/active_record/readonly_attributes.rb +7 -3
- data/lib/active_record/reflection.rb +72 -56
- data/lib/active_record/relation.rb +241 -157
- data/lib/active_record/relation/batches.rb +25 -22
- data/lib/active_record/relation/calculations.rb +143 -121
- data/lib/active_record/relation/delegation.rb +96 -18
- data/lib/active_record/relation/finder_methods.rb +117 -183
- data/lib/active_record/relation/merger.rb +133 -0
- data/lib/active_record/relation/predicate_builder.rb +90 -42
- data/lib/active_record/relation/query_methods.rb +666 -136
- data/lib/active_record/relation/spawn_methods.rb +43 -150
- data/lib/active_record/result.rb +33 -6
- data/lib/active_record/sanitization.rb +24 -50
- data/lib/active_record/schema.rb +19 -12
- data/lib/active_record/schema_dumper.rb +31 -39
- data/lib/active_record/schema_migration.rb +36 -0
- data/lib/active_record/scoping.rb +0 -124
- data/lib/active_record/scoping/default.rb +48 -45
- data/lib/active_record/scoping/named.rb +74 -103
- data/lib/active_record/serialization.rb +6 -2
- data/lib/active_record/serializers/xml_serializer.rb +9 -15
- data/lib/active_record/store.rb +119 -15
- data/lib/active_record/tasks/database_tasks.rb +158 -0
- data/lib/active_record/tasks/mysql_database_tasks.rb +138 -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/test_case.rb +61 -38
- data/lib/active_record/timestamp.rb +8 -9
- data/lib/active_record/transactions.rb +65 -51
- data/lib/active_record/validations.rb +17 -15
- data/lib/active_record/validations/associated.rb +20 -14
- data/lib/active_record/validations/presence.rb +65 -0
- data/lib/active_record/validations/uniqueness.rb +93 -52
- data/lib/active_record/version.rb +4 -4
- data/lib/rails/generators/active_record.rb +3 -5
- data/lib/rails/generators/active_record/migration/migration_generator.rb +37 -7
- data/lib/rails/generators/active_record/migration/templates/migration.rb +20 -15
- data/lib/rails/generators/active_record/model/model_generator.rb +4 -3
- data/lib/rails/generators/active_record/model/templates/model.rb +1 -6
- data/lib/rails/generators/active_record/model/templates/module.rb +1 -1
- metadata +53 -46
- data/lib/active_record/attribute_methods/deprecated_underscore_read.rb +0 -32
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +0 -191
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +0 -583
- data/lib/active_record/dynamic_finder_match.rb +0 -68
- data/lib/active_record/dynamic_scope_match.rb +0 -23
- data/lib/active_record/fixtures/file.rb +0 -65
- data/lib/active_record/identity_map.rb +0 -162
- data/lib/active_record/observer.rb +0 -121
- data/lib/active_record/session_store.rb +0 -360
- data/lib/rails/generators/active_record/migration.rb +0 -15
- data/lib/rails/generators/active_record/observer/observer_generator.rb +0 -15
- data/lib/rails/generators/active_record/observer/templates/observer.rb +0 -4
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +0 -25
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +0 -12
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -49,10 +49,10 @@ A short rundown of some of the major features:
|
|
49
49
|
* Aggregations of value objects.
|
50
50
|
|
51
51
|
class Account < ActiveRecord::Base
|
52
|
-
composed_of :balance, :
|
53
|
-
:
|
52
|
+
composed_of :balance, class_name: 'Money',
|
53
|
+
mapping: %w(balance amount)
|
54
54
|
composed_of :address,
|
55
|
-
:
|
55
|
+
mapping: [%w(address_street street), %w(address_city city)]
|
56
56
|
end
|
57
57
|
|
58
58
|
{Learn more}[link:classes/ActiveRecord/Aggregations/ClassMethods.html]
|
@@ -61,10 +61,10 @@ A short rundown of some of the major features:
|
|
61
61
|
* Validation rules that can differ for new or existing objects.
|
62
62
|
|
63
63
|
class Account < ActiveRecord::Base
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
64
|
+
validates :subdomain, :name, :email_address, :password, presence: true
|
65
|
+
validates :subdomain, uniqueness: true
|
66
|
+
validates :terms_of_service, acceptance: true, on: :create
|
67
|
+
validates :password, :email_address, confirmation: true, on: :create
|
68
68
|
end
|
69
69
|
|
70
70
|
{Learn more}[link:classes/ActiveRecord/Validations.html]
|
@@ -80,17 +80,6 @@ A short rundown of some of the major features:
|
|
80
80
|
{Learn more}[link:classes/ActiveRecord/Callbacks.html]
|
81
81
|
|
82
82
|
|
83
|
-
* Observers that react to changes in a model.
|
84
|
-
|
85
|
-
class CommentObserver < ActiveRecord::Observer
|
86
|
-
def after_create(comment) # is called just after Comment#save
|
87
|
-
CommentMailer.new_comment_email("david@loudthinking.com", comment).deliver
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
{Learn more}[link:classes/ActiveRecord/Observer.html]
|
92
|
-
|
93
|
-
|
94
83
|
* Inheritance hierarchies.
|
95
84
|
|
96
85
|
class Company < ActiveRecord::Base; end
|
@@ -124,15 +113,15 @@ A short rundown of some of the major features:
|
|
124
113
|
* Database abstraction through simple adapters.
|
125
114
|
|
126
115
|
# connect to SQLite3
|
127
|
-
ActiveRecord::Base.establish_connection(:
|
116
|
+
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: 'dbfile.sqlite3')
|
128
117
|
|
129
118
|
# connect to MySQL with authentication
|
130
119
|
ActiveRecord::Base.establish_connection(
|
131
|
-
:
|
132
|
-
:
|
133
|
-
:
|
134
|
-
:
|
135
|
-
:
|
120
|
+
adapter: 'mysql2',
|
121
|
+
host: 'localhost',
|
122
|
+
username: 'me',
|
123
|
+
password: 'secret',
|
124
|
+
database: 'activerecord'
|
136
125
|
)
|
137
126
|
|
138
127
|
{Learn more}[link:classes/ActiveRecord/Base.html] and read about the built-in support for
|
@@ -143,8 +132,8 @@ A short rundown of some of the major features:
|
|
143
132
|
|
144
133
|
* Logging support for Log4r[http://log4r.sourceforge.net] and Logger[http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc].
|
145
134
|
|
146
|
-
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
147
|
-
ActiveRecord::Base.logger = Log4r::Logger.new(
|
135
|
+
ActiveRecord::Base.logger = ActiveSupport::Logger.new(STDOUT)
|
136
|
+
ActiveRecord::Base.logger = Log4r::Logger.new('Application Log')
|
148
137
|
|
149
138
|
|
150
139
|
* Database agnostic schema management with Migrations.
|
@@ -159,7 +148,7 @@ A short rundown of some of the major features:
|
|
159
148
|
t.integer :position
|
160
149
|
end
|
161
150
|
|
162
|
-
SystemSetting.create :
|
151
|
+
SystemSetting.create name: 'notice', label: 'Use notice?', value: 1
|
163
152
|
end
|
164
153
|
|
165
154
|
def down
|
@@ -203,12 +192,14 @@ The latest version of Active Record can be installed with RubyGems:
|
|
203
192
|
|
204
193
|
Source code can be downloaded as part of the Rails project on GitHub
|
205
194
|
|
206
|
-
* https://github.com/rails/rails/tree/
|
195
|
+
* https://github.com/rails/rails/tree/master/activerecord
|
207
196
|
|
208
197
|
|
209
198
|
== License
|
210
199
|
|
211
|
-
Active Record is released under the MIT license
|
200
|
+
Active Record is released under the MIT license:
|
201
|
+
|
202
|
+
* http://www.opensource.org/licenses/MIT
|
212
203
|
|
213
204
|
|
214
205
|
== Support
|
data/examples/performance.rb
CHANGED
data/lib/active_record.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#--
|
2
|
-
# Copyright (c) 2004-
|
2
|
+
# Copyright (c) 2004-2013 David Heinemeier Hansson
|
3
3
|
#
|
4
4
|
# Permission is hereby granted, free of charge, to any person obtaining
|
5
5
|
# a copy of this software and associated documentation files (the
|
@@ -22,24 +22,45 @@
|
|
22
22
|
#++
|
23
23
|
|
24
24
|
require 'active_support'
|
25
|
-
require 'active_support/
|
25
|
+
require 'active_support/rails'
|
26
26
|
require 'active_model'
|
27
27
|
require 'arel'
|
28
|
+
require 'active_record/deprecated_finders'
|
28
29
|
|
29
30
|
require 'active_record/version'
|
30
31
|
|
31
32
|
module ActiveRecord
|
32
33
|
extend ActiveSupport::Autoload
|
33
34
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
autoload :
|
35
|
+
autoload :Base
|
36
|
+
autoload :Callbacks
|
37
|
+
autoload :Core
|
38
|
+
autoload :CounterCache
|
39
|
+
autoload :ConnectionHandling
|
40
|
+
autoload :DynamicMatchers
|
41
|
+
autoload :Explain
|
42
|
+
autoload :Inheritance
|
43
|
+
autoload :Integration
|
44
|
+
autoload :Migration
|
45
|
+
autoload :Migrator, 'active_record/migration'
|
46
|
+
autoload :ModelSchema
|
47
|
+
autoload :NestedAttributes
|
48
|
+
autoload :Persistence
|
49
|
+
autoload :QueryCache
|
50
|
+
autoload :Querying
|
51
|
+
autoload :ReadonlyAttributes
|
52
|
+
autoload :Reflection
|
53
|
+
autoload :Sanitization
|
54
|
+
autoload :Schema
|
55
|
+
autoload :SchemaDumper
|
56
|
+
autoload :SchemaMigration
|
57
|
+
autoload :Scoping
|
58
|
+
autoload :Serialization
|
59
|
+
autoload :Store
|
60
|
+
autoload :Timestamp
|
61
|
+
autoload :Transactions
|
62
|
+
autoload :Translation
|
63
|
+
autoload :Validations
|
43
64
|
|
44
65
|
eager_autoload do
|
45
66
|
autoload :ActiveRecordError, 'active_record/errors'
|
@@ -53,6 +74,7 @@ module ActiveRecord
|
|
53
74
|
autoload :AutosaveAssociation
|
54
75
|
|
55
76
|
autoload :Relation
|
77
|
+
autoload :NullRelation
|
56
78
|
|
57
79
|
autoload_under 'relation' do
|
58
80
|
autoload :QueryMethods
|
@@ -61,41 +83,10 @@ module ActiveRecord
|
|
61
83
|
autoload :PredicateBuilder
|
62
84
|
autoload :SpawnMethods
|
63
85
|
autoload :Batches
|
64
|
-
autoload :Explain
|
65
86
|
autoload :Delegation
|
66
87
|
end
|
67
88
|
|
68
|
-
autoload :Base
|
69
|
-
autoload :Callbacks
|
70
|
-
autoload :CounterCache
|
71
|
-
autoload :DynamicMatchers
|
72
|
-
autoload :DynamicFinderMatch
|
73
|
-
autoload :DynamicScopeMatch
|
74
|
-
autoload :Explain
|
75
|
-
autoload :IdentityMap
|
76
|
-
autoload :Inheritance
|
77
|
-
autoload :Integration
|
78
|
-
autoload :Migration
|
79
|
-
autoload :Migrator, 'active_record/migration'
|
80
|
-
autoload :ModelSchema
|
81
|
-
autoload :NestedAttributes
|
82
|
-
autoload :Observer
|
83
|
-
autoload :Persistence
|
84
|
-
autoload :QueryCache
|
85
|
-
autoload :Querying
|
86
|
-
autoload :ReadonlyAttributes
|
87
|
-
autoload :Reflection
|
88
89
|
autoload :Result
|
89
|
-
autoload :Sanitization
|
90
|
-
autoload :Schema
|
91
|
-
autoload :SchemaDumper
|
92
|
-
autoload :Scoping
|
93
|
-
autoload :Serialization
|
94
|
-
autoload :Store
|
95
|
-
autoload :Timestamp
|
96
|
-
autoload :Transactions
|
97
|
-
autoload :Translation
|
98
|
-
autoload :Validations
|
99
90
|
end
|
100
91
|
|
101
92
|
module Coders
|
@@ -114,7 +105,6 @@ module ActiveRecord
|
|
114
105
|
autoload :TimeZoneConversion
|
115
106
|
autoload :Write
|
116
107
|
autoload :Serialization
|
117
|
-
autoload :DeprecatedUnderscoreRead
|
118
108
|
end
|
119
109
|
end
|
120
110
|
|
@@ -145,12 +135,33 @@ module ActiveRecord
|
|
145
135
|
end
|
146
136
|
end
|
147
137
|
|
138
|
+
module Tasks
|
139
|
+
extend ActiveSupport::Autoload
|
140
|
+
|
141
|
+
autoload :DatabaseTasks
|
142
|
+
autoload :SQLiteDatabaseTasks, 'active_record/tasks/sqlite_database_tasks'
|
143
|
+
autoload :MySQLDatabaseTasks, 'active_record/tasks/mysql_database_tasks'
|
144
|
+
autoload :PostgreSQLDatabaseTasks,
|
145
|
+
'active_record/tasks/postgresql_database_tasks'
|
146
|
+
end
|
147
|
+
|
148
148
|
autoload :TestCase
|
149
149
|
autoload :TestFixtures, 'active_record/fixtures'
|
150
|
+
|
151
|
+
def self.eager_load!
|
152
|
+
super
|
153
|
+
ActiveRecord::Locking.eager_load!
|
154
|
+
ActiveRecord::Scoping.eager_load!
|
155
|
+
ActiveRecord::Associations.eager_load!
|
156
|
+
ActiveRecord::AttributeMethods.eager_load!
|
157
|
+
ActiveRecord::ConnectionAdapters.eager_load!
|
158
|
+
end
|
150
159
|
end
|
151
160
|
|
152
161
|
ActiveSupport.on_load(:active_record) do
|
153
162
|
Arel::Table.engine = self
|
154
163
|
end
|
155
164
|
|
156
|
-
|
165
|
+
ActiveSupport.on_load(:i18n) do
|
166
|
+
I18n.load_path << File.dirname(__FILE__) + '/active_record/locale/en.yml'
|
167
|
+
end
|
@@ -10,14 +10,14 @@ module ActiveRecord
|
|
10
10
|
# Active Record implements aggregation through a macro-like class method called +composed_of+
|
11
11
|
# for representing attributes as value objects. It expresses relationships like "Account [is]
|
12
12
|
# composed of Money [among other things]" or "Person [is] composed of [an] address". Each call
|
13
|
-
# to the macro adds a description of how the value objects
|
14
|
-
# the entity object (when the entity is initialized either
|
15
|
-
# existing object) and how it can be turned back into attributes
|
13
|
+
# to the macro adds a description of how the value objects are created from the attributes of
|
14
|
+
# the entity object (when the entity is initialized either as a new object or from finding an
|
15
|
+
# existing object) and how it can be turned back into attributes (when the entity is saved to
|
16
16
|
# the database).
|
17
17
|
#
|
18
18
|
# class Customer < ActiveRecord::Base
|
19
|
-
# composed_of :balance, :
|
20
|
-
# composed_of :address, :
|
19
|
+
# composed_of :balance, class_name: "Money", mapping: %w(balance amount)
|
20
|
+
# composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
|
21
21
|
# end
|
22
22
|
#
|
23
23
|
# The customer class now has the following methods to manipulate the value objects:
|
@@ -71,7 +71,7 @@ module ActiveRecord
|
|
71
71
|
# Now it's possible to access attributes from the database through the value objects instead. If
|
72
72
|
# you choose to name the composition the same as the attribute's name, it will be the only way to
|
73
73
|
# access that attribute. That's the case with our +balance+ attribute. You interact with the value
|
74
|
-
# objects just like you would any other attribute
|
74
|
+
# objects just like you would with any other attribute:
|
75
75
|
#
|
76
76
|
# customer.balance = Money.new(20) # sets the Money value object and the attribute
|
77
77
|
# customer.balance # => Money value object
|
@@ -86,6 +86,12 @@ module ActiveRecord
|
|
86
86
|
# customer.address_street = "Hyancintvej"
|
87
87
|
# customer.address_city = "Copenhagen"
|
88
88
|
# customer.address # => Address.new("Hyancintvej", "Copenhagen")
|
89
|
+
#
|
90
|
+
# customer.address_street = "Vesterbrogade"
|
91
|
+
# customer.address # => Address.new("Hyancintvej", "Copenhagen")
|
92
|
+
# customer.clear_aggregation_cache
|
93
|
+
# customer.address # => Address.new("Vesterbrogade", "Copenhagen")
|
94
|
+
#
|
89
95
|
# customer.address = Address.new("May Street", "Chicago")
|
90
96
|
# customer.address_street # => "May Street"
|
91
97
|
# customer.address_city # => "Chicago"
|
@@ -101,13 +107,13 @@ module ActiveRecord
|
|
101
107
|
# ActiveRecord::Base classes are entity objects.
|
102
108
|
#
|
103
109
|
# It's also important to treat the value objects as immutable. Don't allow the Money object to have
|
104
|
-
# its amount changed after creation. Create a new Money object with the new value instead.
|
105
|
-
# is
|
110
|
+
# its amount changed after creation. Create a new Money object with the new value instead. The
|
111
|
+
# Money#exchange_to method is an example of this. It returns a new value object instead of changing
|
106
112
|
# its own values. Active Record won't persist value objects that have been changed through means
|
107
113
|
# other than the writer method.
|
108
114
|
#
|
109
115
|
# The immutable requirement is enforced by Active Record by freezing any object assigned as a value
|
110
|
-
# object. Attempting to change it afterwards will result in a
|
116
|
+
# object. Attempting to change it afterwards will result in a RuntimeError.
|
111
117
|
#
|
112
118
|
# Read more about value objects on http://c2.com/cgi/wiki?ValueObject and on the dangers of not
|
113
119
|
# keeping value objects immutable on http://c2.com/cgi/wiki?ValueObjectsShouldBeImmutable
|
@@ -119,7 +125,7 @@ module ActiveRecord
|
|
119
125
|
# option, as arguments. If the value class doesn't support this convention then +composed_of+ allows
|
120
126
|
# a custom constructor to be specified.
|
121
127
|
#
|
122
|
-
# When a new value is assigned to the value object the default assumption is that the new value
|
128
|
+
# When a new value is assigned to the value object, the default assumption is that the new value
|
123
129
|
# is an instance of the value class. Specifying a custom converter allows the new value to be automatically
|
124
130
|
# converted to an instance of value class if necessary.
|
125
131
|
#
|
@@ -132,15 +138,15 @@ module ActiveRecord
|
|
132
138
|
#
|
133
139
|
# class NetworkResource < ActiveRecord::Base
|
134
140
|
# composed_of :cidr,
|
135
|
-
# :
|
136
|
-
# :
|
137
|
-
# :
|
138
|
-
# :
|
139
|
-
# :
|
141
|
+
# class_name: 'NetAddr::CIDR',
|
142
|
+
# mapping: [ %w(network_address network), %w(cidr_range bits) ],
|
143
|
+
# allow_nil: true,
|
144
|
+
# constructor: Proc.new { |network_address, cidr_range| NetAddr::CIDR.create("#{network_address}/#{cidr_range}") },
|
145
|
+
# converter: Proc.new { |value| NetAddr::CIDR.create(value.is_a?(Array) ? value.join('/') : value) }
|
140
146
|
# end
|
141
147
|
#
|
142
148
|
# # This calls the :constructor
|
143
|
-
# network_resource = NetworkResource.new(:
|
149
|
+
# network_resource = NetworkResource.new(network_address: '192.168.0.1', cidr_range: 24)
|
144
150
|
#
|
145
151
|
# # These assignments will both use the :converter
|
146
152
|
# network_resource.cidr = [ '192.168.2.1', 8 ]
|
@@ -159,7 +165,7 @@ module ActiveRecord
|
|
159
165
|
# by specifying an instance of the value object in the conditions hash. The following example
|
160
166
|
# finds all customers with +balance_amount+ equal to 20 and +balance_currency+ equal to "USD":
|
161
167
|
#
|
162
|
-
# Customer.where(:
|
168
|
+
# Customer.where(balance: Money.new(20, "USD"))
|
163
169
|
#
|
164
170
|
module ClassMethods
|
165
171
|
# Adds reader and writer methods for manipulating a value object:
|
@@ -187,20 +193,21 @@ module ActiveRecord
|
|
187
193
|
# * <tt>:converter</tt> - A symbol specifying the name of a class method of <tt>:class_name</tt>
|
188
194
|
# or a Proc that is called when a new value is assigned to the value object. The converter is
|
189
195
|
# passed the single value that is used in the assignment and is only called if the new value is
|
190
|
-
# not an instance of <tt>:class_name</tt>.
|
196
|
+
# not an instance of <tt>:class_name</tt>. If <tt>:allow_nil</tt> is set to true, the converter
|
197
|
+
# can return nil to skip the assignment.
|
191
198
|
#
|
192
199
|
# Option examples:
|
193
|
-
# composed_of :temperature, :
|
194
|
-
# composed_of :balance, :
|
195
|
-
# :
|
196
|
-
# composed_of :address, :
|
200
|
+
# composed_of :temperature, mapping: %w(reading celsius)
|
201
|
+
# composed_of :balance, class_name: "Money", mapping: %w(balance amount),
|
202
|
+
# converter: Proc.new { |balance| balance.to_money }
|
203
|
+
# composed_of :address, mapping: [ %w(address_street street), %w(address_city city) ]
|
197
204
|
# composed_of :gps_location
|
198
|
-
# composed_of :gps_location, :
|
205
|
+
# composed_of :gps_location, allow_nil: true
|
199
206
|
# composed_of :ip_address,
|
200
|
-
# :
|
201
|
-
# :
|
202
|
-
# :
|
203
|
-
# :
|
207
|
+
# class_name: 'IPAddr',
|
208
|
+
# mapping: %w(ip to_i),
|
209
|
+
# constructor: Proc.new { |ip| IPAddr.new(ip, Socket::AF_INET) },
|
210
|
+
# converter: Proc.new { |ip| ip.is_a?(Integer) ? IPAddr.new(ip, Socket::AF_INET) : IPAddr.new(ip.to_s) }
|
204
211
|
#
|
205
212
|
def composed_of(part_id, options = {})
|
206
213
|
options.assert_valid_keys(:class_name, :mapping, :allow_nil, :constructor, :converter)
|
@@ -216,7 +223,7 @@ module ActiveRecord
|
|
216
223
|
reader_method(name, class_name, mapping, allow_nil, constructor)
|
217
224
|
writer_method(name, class_name, mapping, allow_nil, converter)
|
218
225
|
|
219
|
-
create_reflection(:composed_of, part_id, options, self)
|
226
|
+
create_reflection(:composed_of, part_id, nil, options, self)
|
220
227
|
end
|
221
228
|
|
222
229
|
private
|
@@ -235,16 +242,15 @@ module ActiveRecord
|
|
235
242
|
|
236
243
|
def writer_method(name, class_name, mapping, allow_nil, converter)
|
237
244
|
define_method("#{name}=") do |part|
|
245
|
+
klass = class_name.constantize
|
246
|
+
unless part.is_a?(klass) || converter.nil? || part.nil?
|
247
|
+
part = converter.respond_to?(:call) ? converter.call(part) : klass.send(converter, part)
|
248
|
+
end
|
249
|
+
|
238
250
|
if part.nil? && allow_nil
|
239
251
|
mapping.each { |pair| self[pair.first] = nil }
|
240
252
|
@aggregation_cache[name] = nil
|
241
253
|
else
|
242
|
-
unless part.is_a?(class_name.constantize) || converter.nil?
|
243
|
-
part = converter.respond_to?(:call) ?
|
244
|
-
converter.call(part) :
|
245
|
-
class_name.constantize.send(converter, part)
|
246
|
-
end
|
247
|
-
|
248
254
|
mapping.each { |pair| self[pair.first] = part.send(pair.last) }
|
249
255
|
@aggregation_cache[name] = part.freeze
|
250
256
|
end
|
@@ -1,10 +1,7 @@
|
|
1
|
-
require 'active_support/core_ext/array/wrap'
|
2
1
|
require 'active_support/core_ext/enumerable'
|
3
|
-
require 'active_support/core_ext/module/delegation'
|
4
|
-
require 'active_support/core_ext/object/blank'
|
5
2
|
require 'active_support/core_ext/string/conversions'
|
6
3
|
require 'active_support/core_ext/module/remove_method'
|
7
|
-
require '
|
4
|
+
require 'active_record/errors'
|
8
5
|
|
9
6
|
module ActiveRecord
|
10
7
|
class InverseOfAssociationNotFoundError < ActiveRecordError #:nodoc:
|
@@ -21,7 +18,7 @@ module ActiveRecord
|
|
21
18
|
|
22
19
|
class HasManyThroughAssociationPolymorphicSourceError < ActiveRecordError #:nodoc:
|
23
20
|
def initialize(owner_class_name, reflection, source_reflection)
|
24
|
-
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' on the polymorphic object '#{source_reflection.class_name}##{source_reflection.name}'.")
|
21
|
+
super("Cannot have a has_many :through association '#{owner_class_name}##{reflection.name}' on the polymorphic object '#{source_reflection.class_name}##{source_reflection.name}' without 'source_type'. Try adding 'source_type: \"#{reflection.name.to_s.classify}\"' to 'has_many :through' definition.")
|
25
22
|
end
|
26
23
|
end
|
27
24
|
|
@@ -194,30 +191,10 @@ module ActiveRecord
|
|
194
191
|
# * <tt>Project#portfolio, Project#portfolio=(portfolio), Project#portfolio.nil?</tt>
|
195
192
|
# * <tt>Project#project_manager, Project#project_manager=(project_manager), Project#project_manager.nil?,</tt>
|
196
193
|
# * <tt>Project#milestones.empty?, Project#milestones.size, Project#milestones, Project#milestones<<(milestone),</tt>
|
197
|
-
# <tt>Project#milestones.delete(milestone), Project#milestones.
|
194
|
+
# <tt>Project#milestones.delete(milestone), Project#milestones.destroy(milestone), Project#milestones.find(milestone_id),</tt>
|
198
195
|
# <tt>Project#milestones.build, Project#milestones.create</tt>
|
199
196
|
# * <tt>Project#categories.empty?, Project#categories.size, Project#categories, Project#categories<<(category1),</tt>
|
200
|
-
# <tt>Project#categories.delete(category1)</tt>
|
201
|
-
#
|
202
|
-
# === Overriding generated methods
|
203
|
-
#
|
204
|
-
# Association methods are generated in a module that is included into the model class,
|
205
|
-
# which allows you to easily override with your own methods and call the original
|
206
|
-
# generated method with +super+. For example:
|
207
|
-
#
|
208
|
-
# class Car < ActiveRecord::Base
|
209
|
-
# belongs_to :owner
|
210
|
-
# belongs_to :old_owner
|
211
|
-
# def owner=(new_owner)
|
212
|
-
# self.old_owner = self.owner
|
213
|
-
# super
|
214
|
-
# end
|
215
|
-
# end
|
216
|
-
#
|
217
|
-
# If your model class is <tt>Project</tt>, the module is
|
218
|
-
# named <tt>Project::GeneratedFeatureMethods</tt>. The GeneratedFeatureMethods module is
|
219
|
-
# included in the model class immediately after the (anonymous) generated attributes methods
|
220
|
-
# module, meaning an association will override the methods for an attribute with the same name.
|
197
|
+
# <tt>Project#categories.delete(category1), Project#categories.destroy(category1)</tt>
|
221
198
|
#
|
222
199
|
# === A word of warning
|
223
200
|
#
|
@@ -255,17 +232,38 @@ module ActiveRecord
|
|
255
232
|
# others.size | X | X | X
|
256
233
|
# others.length | X | X | X
|
257
234
|
# others.count | X | X | X
|
258
|
-
# others.sum(args
|
235
|
+
# others.sum(*args) | X | X | X
|
259
236
|
# others.empty? | X | X | X
|
260
237
|
# others.clear | X | X | X
|
261
238
|
# others.delete(other,other,...) | X | X | X
|
262
239
|
# others.delete_all | X | X | X
|
240
|
+
# others.destroy(other,other,...) | X | X | X
|
263
241
|
# others.destroy_all | X | X | X
|
264
242
|
# others.find(*args) | X | X | X
|
265
243
|
# others.exists? | X | X | X
|
266
244
|
# others.uniq | X | X | X
|
267
245
|
# others.reset | X | X | X
|
268
246
|
#
|
247
|
+
# === Overriding generated methods
|
248
|
+
#
|
249
|
+
# Association methods are generated in a module that is included into the model class,
|
250
|
+
# which allows you to easily override with your own methods and call the original
|
251
|
+
# generated method with +super+. For example:
|
252
|
+
#
|
253
|
+
# class Car < ActiveRecord::Base
|
254
|
+
# belongs_to :owner
|
255
|
+
# belongs_to :old_owner
|
256
|
+
# def owner=(new_owner)
|
257
|
+
# self.old_owner = self.owner
|
258
|
+
# super
|
259
|
+
# end
|
260
|
+
# end
|
261
|
+
#
|
262
|
+
# If your model class is <tt>Project</tt>, the module is
|
263
|
+
# named <tt>Project::GeneratedFeatureMethods</tt>. The GeneratedFeatureMethods module is
|
264
|
+
# included in the model class immediately after the (anonymous) generated attributes methods
|
265
|
+
# module, meaning an association will override the methods for an attribute with the same name.
|
266
|
+
#
|
269
267
|
# == Cardinality and associations
|
270
268
|
#
|
271
269
|
# Active Record associations can be used to describe one-to-one, one-to-many and many-to-many
|
@@ -308,11 +306,11 @@ module ActiveRecord
|
|
308
306
|
# end
|
309
307
|
# class Programmer < ActiveRecord::Base
|
310
308
|
# has_many :assignments
|
311
|
-
# has_many :projects, :
|
309
|
+
# has_many :projects, through: :assignments
|
312
310
|
# end
|
313
311
|
# class Project < ActiveRecord::Base
|
314
312
|
# has_many :assignments
|
315
|
-
# has_many :programmers, :
|
313
|
+
# has_many :programmers, through: :assignments
|
316
314
|
# end
|
317
315
|
#
|
318
316
|
# For the second way, use +has_and_belongs_to_many+ in both models. This requires a join table
|
@@ -401,14 +399,35 @@ module ActiveRecord
|
|
401
399
|
# * All unsaved (<tt>new_record? == true</tt>) members of the collection are automatically
|
402
400
|
# saved when the parent is saved.
|
403
401
|
#
|
404
|
-
#
|
402
|
+
# == Customizing the query
|
403
|
+
#
|
404
|
+
# Associations are built from <tt>Relation</tt>s, and you can use the <tt>Relation</tt> syntax
|
405
|
+
# to customize them. For example, to add a condition:
|
406
|
+
#
|
407
|
+
# class Blog < ActiveRecord::Base
|
408
|
+
# has_many :published_posts, -> { where published: true }, class_name: 'Post'
|
409
|
+
# end
|
410
|
+
#
|
411
|
+
# Inside the <tt>-> { ... }</tt> block you can use all of the usual <tt>Relation</tt> methods.
|
412
|
+
#
|
413
|
+
# === Accessing the owner object
|
414
|
+
#
|
415
|
+
# Sometimes it is useful to have access to the owner object when building the query. The owner
|
416
|
+
# is passed as a parameter to the block. For example, the following association would find all
|
417
|
+
# events that occur on the user's birthday:
|
418
|
+
#
|
419
|
+
# class User < ActiveRecord::Base
|
420
|
+
# has_many :birthday_events, ->(user) { where starts_on: user.birthday }, class_name: 'Event'
|
421
|
+
# end
|
422
|
+
#
|
423
|
+
# == Association callbacks
|
405
424
|
#
|
406
425
|
# Similar to the normal callbacks that hook into the life cycle of an Active Record object,
|
407
426
|
# you can also define callbacks that get triggered when you add an object to or remove an
|
408
427
|
# object from an association collection.
|
409
428
|
#
|
410
429
|
# class Project
|
411
|
-
# has_and_belongs_to_many :developers, :
|
430
|
+
# has_and_belongs_to_many :developers, after_add: :evaluate_velocity
|
412
431
|
#
|
413
432
|
# def evaluate_velocity(developer)
|
414
433
|
# ...
|
@@ -419,7 +438,7 @@ module ActiveRecord
|
|
419
438
|
#
|
420
439
|
# class Project
|
421
440
|
# has_and_belongs_to_many :developers,
|
422
|
-
# :
|
441
|
+
# after_add: [:evaluate_velocity, Proc.new { |p, d| p.shipping_date = Time.now}]
|
423
442
|
# end
|
424
443
|
#
|
425
444
|
# Possible callbacks are: +before_add+, +after_add+, +before_remove+ and +after_remove+.
|
@@ -428,7 +447,7 @@ module ActiveRecord
|
|
428
447
|
# added to the collection. Same with the +before_remove+ callbacks; if an exception is
|
429
448
|
# thrown the object doesn't get removed.
|
430
449
|
#
|
431
|
-
#
|
450
|
+
# == Association extensions
|
432
451
|
#
|
433
452
|
# The proxy objects that control the access to associations can be extended through anonymous
|
434
453
|
# modules. This is especially beneficial for adding new finders, creators, and other
|
@@ -438,7 +457,7 @@ module ActiveRecord
|
|
438
457
|
# has_many :people do
|
439
458
|
# def find_or_create_by_name(name)
|
440
459
|
# first_name, last_name = name.split(" ", 2)
|
441
|
-
#
|
460
|
+
# find_or_create_by(first_name: first_name, last_name: last_name)
|
442
461
|
# end
|
443
462
|
# end
|
444
463
|
# end
|
@@ -453,25 +472,16 @@ module ActiveRecord
|
|
453
472
|
# module FindOrCreateByNameExtension
|
454
473
|
# def find_or_create_by_name(name)
|
455
474
|
# first_name, last_name = name.split(" ", 2)
|
456
|
-
#
|
475
|
+
# find_or_create_by(first_name: first_name, last_name: last_name)
|
457
476
|
# end
|
458
477
|
# end
|
459
478
|
#
|
460
479
|
# class Account < ActiveRecord::Base
|
461
|
-
# has_many :people,
|
480
|
+
# has_many :people, -> { extending FindOrCreateByNameExtension }
|
462
481
|
# end
|
463
482
|
#
|
464
483
|
# class Company < ActiveRecord::Base
|
465
|
-
# has_many :people,
|
466
|
-
# end
|
467
|
-
#
|
468
|
-
# If you need to use multiple named extension modules, you can specify an array of modules
|
469
|
-
# with the <tt>:extend</tt> option.
|
470
|
-
# In the case of name conflicts between methods in the modules, methods in modules later
|
471
|
-
# in the array supercede those earlier in the array.
|
472
|
-
#
|
473
|
-
# class Account < ActiveRecord::Base
|
474
|
-
# has_many :people, :extend => [FindOrCreateByNameExtension, FindRecentExtension]
|
484
|
+
# has_many :people, -> { extending FindOrCreateByNameExtension }
|
475
485
|
# end
|
476
486
|
#
|
477
487
|
# Some extensions can only be made to work with knowledge of the association's internals.
|
@@ -489,7 +499,7 @@ module ActiveRecord
|
|
489
499
|
# the same object, allowing you to make calls like <tt>proxy_association.owner</tt> inside
|
490
500
|
# association extensions.
|
491
501
|
#
|
492
|
-
#
|
502
|
+
# == Association Join Models
|
493
503
|
#
|
494
504
|
# Has Many associations can be configured with the <tt>:through</tt> option to use an
|
495
505
|
# explicit join model to retrieve the data. This operates similarly to a
|
@@ -498,7 +508,7 @@ module ActiveRecord
|
|
498
508
|
#
|
499
509
|
# class Author < ActiveRecord::Base
|
500
510
|
# has_many :authorships
|
501
|
-
# has_many :books, :
|
511
|
+
# has_many :books, through: :authorships
|
502
512
|
# end
|
503
513
|
#
|
504
514
|
# class Authorship < ActiveRecord::Base
|
@@ -514,7 +524,7 @@ module ActiveRecord
|
|
514
524
|
#
|
515
525
|
# class Firm < ActiveRecord::Base
|
516
526
|
# has_many :clients
|
517
|
-
# has_many :invoices, :
|
527
|
+
# has_many :invoices, through: :clients
|
518
528
|
# end
|
519
529
|
#
|
520
530
|
# class Client < ActiveRecord::Base
|
@@ -534,7 +544,7 @@ module ActiveRecord
|
|
534
544
|
#
|
535
545
|
# class Group < ActiveRecord::Base
|
536
546
|
# has_many :users
|
537
|
-
# has_many :avatars, :
|
547
|
+
# has_many :avatars, through: :users
|
538
548
|
# end
|
539
549
|
#
|
540
550
|
# class User < ActiveRecord::Base
|
@@ -547,7 +557,7 @@ module ActiveRecord
|
|
547
557
|
# end
|
548
558
|
#
|
549
559
|
# @group = Group.first
|
550
|
-
# @group.users.collect { |u| u.avatar }.
|
560
|
+
# @group.users.collect { |u| u.avatar }.compact # select all avatars for all users in the group
|
551
561
|
# @group.avatars # selects all avatars by going through the User join model.
|
552
562
|
#
|
553
563
|
# An important caveat with going through +has_one+ or +has_many+ associations on the
|
@@ -562,7 +572,7 @@ module ActiveRecord
|
|
562
572
|
# works correctly (where <tt>tags</tt> is a +has_many+ <tt>:through</tt> association):
|
563
573
|
#
|
564
574
|
# @post = Post.first
|
565
|
-
# @tag = @post.tags.build :
|
575
|
+
# @tag = @post.tags.build name: "ruby"
|
566
576
|
# @tag.save
|
567
577
|
#
|
568
578
|
# The last line ought to save the through record (a <tt>Taggable</tt>). This will only work if the
|
@@ -570,18 +580,18 @@ module ActiveRecord
|
|
570
580
|
#
|
571
581
|
# class Taggable < ActiveRecord::Base
|
572
582
|
# belongs_to :post
|
573
|
-
# belongs_to :tag, :
|
583
|
+
# belongs_to :tag, inverse_of: :taggings
|
574
584
|
# end
|
575
585
|
#
|
576
|
-
#
|
586
|
+
# == Nested Associations
|
577
587
|
#
|
578
588
|
# You can actually specify *any* association with the <tt>:through</tt> option, including an
|
579
589
|
# association which has a <tt>:through</tt> option itself. For example:
|
580
590
|
#
|
581
591
|
# class Author < ActiveRecord::Base
|
582
592
|
# has_many :posts
|
583
|
-
# has_many :comments, :
|
584
|
-
# has_many :commenters, :
|
593
|
+
# has_many :comments, through: :posts
|
594
|
+
# has_many :commenters, through: :comments
|
585
595
|
# end
|
586
596
|
#
|
587
597
|
# class Post < ActiveRecord::Base
|
@@ -599,12 +609,12 @@ module ActiveRecord
|
|
599
609
|
#
|
600
610
|
# class Author < ActiveRecord::Base
|
601
611
|
# has_many :posts
|
602
|
-
# has_many :commenters, :
|
612
|
+
# has_many :commenters, through: :posts
|
603
613
|
# end
|
604
614
|
#
|
605
615
|
# class Post < ActiveRecord::Base
|
606
616
|
# has_many :comments
|
607
|
-
# has_many :commenters, :
|
617
|
+
# has_many :commenters, through: :comments
|
608
618
|
# end
|
609
619
|
#
|
610
620
|
# class Comment < ActiveRecord::Base
|
@@ -616,18 +626,18 @@ module ActiveRecord
|
|
616
626
|
# add a <tt>Commenter</tt> in the example above, there would be no way to tell how to set up the
|
617
627
|
# intermediate <tt>Post</tt> and <tt>Comment</tt> objects.
|
618
628
|
#
|
619
|
-
#
|
629
|
+
# == Polymorphic Associations
|
620
630
|
#
|
621
631
|
# Polymorphic associations on models are not restricted on what types of models they
|
622
632
|
# can be associated with. Rather, they specify an interface that a +has_many+ association
|
623
633
|
# must adhere to.
|
624
634
|
#
|
625
635
|
# class Asset < ActiveRecord::Base
|
626
|
-
# belongs_to :attachable, :
|
636
|
+
# belongs_to :attachable, polymorphic: true
|
627
637
|
# end
|
628
638
|
#
|
629
639
|
# class Post < ActiveRecord::Base
|
630
|
-
# has_many :assets, :
|
640
|
+
# has_many :assets, as: :attachable # The :as option specifies the polymorphic interface to use.
|
631
641
|
# end
|
632
642
|
#
|
633
643
|
# @asset.attachable = @post
|
@@ -644,7 +654,7 @@ module ActiveRecord
|
|
644
654
|
# column in the posts table.
|
645
655
|
#
|
646
656
|
# class Asset < ActiveRecord::Base
|
647
|
-
# belongs_to :attachable, :
|
657
|
+
# belongs_to :attachable, polymorphic: true
|
648
658
|
#
|
649
659
|
# def attachable_type=(sType)
|
650
660
|
# super(sType.to_s.classify.constantize.base_class.to_s)
|
@@ -652,8 +662,8 @@ module ActiveRecord
|
|
652
662
|
# end
|
653
663
|
#
|
654
664
|
# class Post < ActiveRecord::Base
|
655
|
-
# # because we store "Post" in attachable_type now :
|
656
|
-
# has_many :assets, :
|
665
|
+
# # because we store "Post" in attachable_type now dependent: :destroy will work
|
666
|
+
# has_many :assets, as: :attachable, dependent: :destroy
|
657
667
|
# end
|
658
668
|
#
|
659
669
|
# class GuestPost < Post
|
@@ -715,7 +725,7 @@ module ActiveRecord
|
|
715
725
|
#
|
716
726
|
# To include a deep hierarchy of associations, use a hash:
|
717
727
|
#
|
718
|
-
# Post.includes(:author, {:
|
728
|
+
# Post.includes(:author, {comments: {author: :gravatar}}).each do |post|
|
719
729
|
#
|
720
730
|
# That'll grab not only all the comments but all their authors and gravatar pictures.
|
721
731
|
# You can mix and match symbols, arrays and hashes in any combination to describe the
|
@@ -731,7 +741,7 @@ module ActiveRecord
|
|
731
741
|
# other than the main one. If this is the case Active Record falls back to the previously
|
732
742
|
# used LEFT OUTER JOIN based strategy. For example
|
733
743
|
#
|
734
|
-
# Post.includes([:author, :comments]).where(['comments.approved = ?', true])
|
744
|
+
# Post.includes([:author, :comments]).where(['comments.approved = ?', true])
|
735
745
|
#
|
736
746
|
# This will result in a single SQL query with joins along the lines of:
|
737
747
|
# <tt>LEFT OUTER JOIN comments ON comments.post_id = posts.id</tt> and
|
@@ -740,13 +750,13 @@ module ActiveRecord
|
|
740
750
|
# In the above example posts with no approved comments are not returned at all, because
|
741
751
|
# the conditions apply to the SQL statement as a whole and not just to the association.
|
742
752
|
# You must disambiguate column references for this fallback to happen, for example
|
743
|
-
# <tt
|
753
|
+
# <tt>order: "author.name DESC"</tt> will work but <tt>order: "name DESC"</tt> will not.
|
744
754
|
#
|
745
755
|
# If you do want eager load only some members of an association it is usually more natural
|
746
756
|
# to include an association which has conditions defined on it:
|
747
757
|
#
|
748
758
|
# class Post < ActiveRecord::Base
|
749
|
-
# has_many :approved_comments,
|
759
|
+
# has_many :approved_comments, -> { where approved: true }, class_name: 'Comment'
|
750
760
|
# end
|
751
761
|
#
|
752
762
|
# Post.includes(:approved_comments)
|
@@ -758,18 +768,15 @@ module ActiveRecord
|
|
758
768
|
# returning all the associated objects:
|
759
769
|
#
|
760
770
|
# class Picture < ActiveRecord::Base
|
761
|
-
# has_many :most_recent_comments,
|
771
|
+
# has_many :most_recent_comments, -> { order('id DESC').limit(10) }, class_name: 'Comment'
|
762
772
|
# end
|
763
773
|
#
|
764
774
|
# Picture.includes(:most_recent_comments).first.most_recent_comments # => returns all associated comments.
|
765
775
|
#
|
766
|
-
# When eager loaded, conditions are interpolated in the context of the model class, not
|
767
|
-
# the model instance. Conditions are lazily interpolated before the actual model exists.
|
768
|
-
#
|
769
776
|
# Eager loading is supported with polymorphic associations.
|
770
777
|
#
|
771
778
|
# class Address < ActiveRecord::Base
|
772
|
-
# belongs_to :addressable, :
|
779
|
+
# belongs_to :addressable, polymorphic: true
|
773
780
|
# end
|
774
781
|
#
|
775
782
|
# A call that tries to eager load the addressable model
|
@@ -803,10 +810,10 @@ module ActiveRecord
|
|
803
810
|
#
|
804
811
|
# TreeMixin.joins(:children)
|
805
812
|
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
806
|
-
# TreeMixin.joins(:
|
813
|
+
# TreeMixin.joins(children: :parent)
|
807
814
|
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
808
815
|
# INNER JOIN parents_mixins ...
|
809
|
-
# TreeMixin.joins(:
|
816
|
+
# TreeMixin.joins(children: {parent: :children})
|
810
817
|
# # => SELECT ... FROM mixins INNER JOIN mixins childrens_mixins ...
|
811
818
|
# INNER JOIN parents_mixins ...
|
812
819
|
# INNER JOIN mixins childrens_mixins_2
|
@@ -815,10 +822,10 @@ module ActiveRecord
|
|
815
822
|
#
|
816
823
|
# Post.joins(:categories)
|
817
824
|
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
818
|
-
# Post.joins(:
|
825
|
+
# Post.joins(categories: :posts)
|
819
826
|
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
820
827
|
# INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
|
821
|
-
# Post.joins(:
|
828
|
+
# Post.joins(categories: {posts: :categories})
|
822
829
|
# # => SELECT ... FROM posts INNER JOIN categories_posts ... INNER JOIN categories ...
|
823
830
|
# INNER JOIN categories_posts posts_categories_join INNER JOIN posts posts_categories
|
824
831
|
# INNER JOIN categories_posts categories_posts_join INNER JOIN categories categories_posts_2
|
@@ -843,8 +850,8 @@ module ActiveRecord
|
|
843
850
|
# module MyApplication
|
844
851
|
# module Business
|
845
852
|
# class Firm < ActiveRecord::Base
|
846
|
-
#
|
847
|
-
#
|
853
|
+
# has_many :clients
|
854
|
+
# end
|
848
855
|
#
|
849
856
|
# class Client < ActiveRecord::Base; end
|
850
857
|
# end
|
@@ -862,7 +869,7 @@ module ActiveRecord
|
|
862
869
|
#
|
863
870
|
# module Billing
|
864
871
|
# class Account < ActiveRecord::Base
|
865
|
-
# belongs_to :firm, :
|
872
|
+
# belongs_to :firm, class_name: "MyApplication::Business::Firm"
|
866
873
|
# end
|
867
874
|
# end
|
868
875
|
# end
|
@@ -904,16 +911,16 @@ module ActiveRecord
|
|
904
911
|
# example, if we changed our model definitions to:
|
905
912
|
#
|
906
913
|
# class Dungeon < ActiveRecord::Base
|
907
|
-
# has_many :traps, :
|
908
|
-
# has_one :evil_wizard, :
|
914
|
+
# has_many :traps, inverse_of: :dungeon
|
915
|
+
# has_one :evil_wizard, inverse_of: :dungeon
|
909
916
|
# end
|
910
917
|
#
|
911
918
|
# class Trap < ActiveRecord::Base
|
912
|
-
# belongs_to :dungeon, :
|
919
|
+
# belongs_to :dungeon, inverse_of: :traps
|
913
920
|
# end
|
914
921
|
#
|
915
922
|
# class EvilWizard < ActiveRecord::Base
|
916
|
-
# belongs_to :dungeon, :
|
923
|
+
# belongs_to :dungeon, inverse_of: :evil_wizard
|
917
924
|
# end
|
918
925
|
#
|
919
926
|
# Then, from our code snippet above, +d+ and <tt>t.dungeon</tt> are actually the same
|
@@ -936,13 +943,19 @@ module ActiveRecord
|
|
936
943
|
# For example:
|
937
944
|
#
|
938
945
|
# class Author
|
939
|
-
# has_many :posts, :
|
946
|
+
# has_many :posts, dependent: :destroy
|
940
947
|
# end
|
941
948
|
# Author.find(1).destroy # => Will destroy all of the author's posts, too
|
942
949
|
#
|
943
950
|
# The <tt>:dependent</tt> option can have different values which specify how the deletion
|
944
951
|
# is done. For more information, see the documentation for this option on the different
|
945
|
-
# specific association types.
|
952
|
+
# specific association types. When no option is given, the behavior is to do nothing
|
953
|
+
# with the associated records when destroying a record.
|
954
|
+
#
|
955
|
+
# Note that <tt>:dependent</tt> is implemented using Rails' callback
|
956
|
+
# system, which works by processing callbacks in order. Therefore, other
|
957
|
+
# callbacks declared either before or after the <tt>:dependent</tt> option
|
958
|
+
# can affect what it does.
|
946
959
|
#
|
947
960
|
# === Delete or destroy?
|
948
961
|
#
|
@@ -952,8 +965,8 @@ module ActiveRecord
|
|
952
965
|
# For +has_and_belongs_to_many+, <tt>delete</tt> and <tt>destroy</tt> are the same: they
|
953
966
|
# cause the records in the join table to be removed.
|
954
967
|
#
|
955
|
-
# For +has_many+, <tt>destroy</tt> will always call the <tt>destroy</tt> method of the
|
956
|
-
# record(s) being removed so that callbacks are run. However <tt>delete</tt> will either
|
968
|
+
# For +has_many+, <tt>destroy</tt> and <tt>destory_all</tt> will always call the <tt>destroy</tt> method of the
|
969
|
+
# record(s) being removed so that callbacks are run. However <tt>delete</tt> and <tt>delete_all</tt> will either
|
957
970
|
# do the deletion according to the strategy specified by the <tt>:dependent</tt> option, or
|
958
971
|
# if no <tt>:dependent</tt> option is given, then it will follow the default strategy.
|
959
972
|
# The default strategy is <tt>:nullify</tt> (set the foreign keys to <tt>nil</tt>), except for
|
@@ -1014,12 +1027,18 @@ module ActiveRecord
|
|
1014
1027
|
# parent object.
|
1015
1028
|
# [collection.delete(object, ...)]
|
1016
1029
|
# Removes one or more objects from the collection by setting their foreign keys to +NULL+.
|
1017
|
-
# Objects will be in addition destroyed if they're associated with <tt
|
1018
|
-
# and deleted if they're associated with <tt
|
1030
|
+
# Objects will be in addition destroyed if they're associated with <tt>dependent: :destroy</tt>,
|
1031
|
+
# and deleted if they're associated with <tt>dependent: :delete_all</tt>.
|
1019
1032
|
#
|
1020
1033
|
# If the <tt>:through</tt> option is used, then the join records are deleted (rather than
|
1021
|
-
# nullified) by default, but you can specify <tt
|
1022
|
-
# <tt
|
1034
|
+
# nullified) by default, but you can specify <tt>dependent: :destroy</tt> or
|
1035
|
+
# <tt>dependent: :nullify</tt> to override this.
|
1036
|
+
# [collection.destroy(object, ...)]
|
1037
|
+
# Removes one or more objects from the collection by running <tt>destroy</tt> on
|
1038
|
+
# each record, regardless of any dependent option, ensuring callbacks are run.
|
1039
|
+
#
|
1040
|
+
# If the <tt>:through</tt> option is used, then the join records are destroyed
|
1041
|
+
# instead, not the objects themselves.
|
1023
1042
|
# [collection=objects]
|
1024
1043
|
# Replaces the collections content by deleting and adding objects as appropriate. If the <tt>:through</tt>
|
1025
1044
|
# option is true callbacks in the join models are triggered except destroy callbacks, since deletion is
|
@@ -1031,8 +1050,8 @@ module ActiveRecord
|
|
1031
1050
|
# method loads the models and calls <tt>collection=</tt>. See above.
|
1032
1051
|
# [collection.clear]
|
1033
1052
|
# Removes every object from the collection. This destroys the associated objects if they
|
1034
|
-
# are associated with <tt
|
1035
|
-
# database if <tt
|
1053
|
+
# are associated with <tt>dependent: :destroy</tt>, deletes them directly from the
|
1054
|
+
# database if <tt>dependent: :delete_all</tt>, otherwise sets their foreign keys to +NULL+.
|
1036
1055
|
# If the <tt>:through</tt> option is true no destroy callbacks are invoked on the join models.
|
1037
1056
|
# Join models are directly deleted.
|
1038
1057
|
# [collection.empty?]
|
@@ -1060,17 +1079,18 @@ module ActiveRecord
|
|
1060
1079
|
# === Example
|
1061
1080
|
#
|
1062
1081
|
# Example: A Firm class declares <tt>has_many :clients</tt>, which will add:
|
1063
|
-
# * <tt>Firm#clients</tt> (similar to <tt>
|
1082
|
+
# * <tt>Firm#clients</tt> (similar to <tt>Client.where(firm_id: id)</tt>)
|
1064
1083
|
# * <tt>Firm#clients<<</tt>
|
1065
1084
|
# * <tt>Firm#clients.delete</tt>
|
1085
|
+
# * <tt>Firm#clients.destroy</tt>
|
1066
1086
|
# * <tt>Firm#clients=</tt>
|
1067
1087
|
# * <tt>Firm#client_ids</tt>
|
1068
1088
|
# * <tt>Firm#client_ids=</tt>
|
1069
1089
|
# * <tt>Firm#clients.clear</tt>
|
1070
1090
|
# * <tt>Firm#clients.empty?</tt> (similar to <tt>firm.clients.size == 0</tt>)
|
1071
1091
|
# * <tt>Firm#clients.size</tt> (similar to <tt>Client.count "firm_id = #{id}"</tt>)
|
1072
|
-
# * <tt>Firm#clients.find</tt> (similar to <tt>Client.
|
1073
|
-
# * <tt>Firm#clients.exists?(:
|
1092
|
+
# * <tt>Firm#clients.find</tt> (similar to <tt>Client.where(firm_id: id).find(id)</tt>)
|
1093
|
+
# * <tt>Firm#clients.exists?(name: 'ACME')</tt> (similar to <tt>Client.exists?(name: 'ACME', firm_id: firm.id)</tt>)
|
1074
1094
|
# * <tt>Firm#clients.build</tt> (similar to <tt>Client.new("firm_id" => id)</tt>)
|
1075
1095
|
# * <tt>Firm#clients.create</tt> (similar to <tt>c = Client.new("firm_id" => id); c.save; c</tt>)
|
1076
1096
|
# The declaration can also include an options hash to specialize the behavior of the association.
|
@@ -1081,15 +1101,6 @@ module ActiveRecord
|
|
1081
1101
|
# from the association name. So <tt>has_many :products</tt> will by default be linked
|
1082
1102
|
# to the Product class, but if the real class name is SpecialProduct, you'll have to
|
1083
1103
|
# specify it with this option.
|
1084
|
-
# [:conditions]
|
1085
|
-
# Specify the conditions that the associated objects must meet in order to be included as a +WHERE+
|
1086
|
-
# SQL fragment, such as <tt>price > 5 AND name LIKE 'B%'</tt>. Record creations from
|
1087
|
-
# the association are scoped if a hash is used.
|
1088
|
-
# <tt>has_many :posts, :conditions => {:published => true}</tt> will create published
|
1089
|
-
# posts with <tt>@blog.posts.create</tt> or <tt>@blog.posts.build</tt>.
|
1090
|
-
# [:order]
|
1091
|
-
# Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
|
1092
|
-
# such as <tt>last_name, first_name DESC</tt>.
|
1093
1104
|
# [:foreign_key]
|
1094
1105
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
1095
1106
|
# of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_many+
|
@@ -1097,44 +1108,24 @@ module ActiveRecord
|
|
1097
1108
|
# [:primary_key]
|
1098
1109
|
# Specify the method that returns the primary key used for the association. By default this is +id+.
|
1099
1110
|
# [:dependent]
|
1100
|
-
#
|
1101
|
-
#
|
1102
|
-
#
|
1103
|
-
#
|
1104
|
-
#
|
1105
|
-
#
|
1111
|
+
# Controls what happens to the associated objects when
|
1112
|
+
# their owner is destroyed. Note that these are implemented as
|
1113
|
+
# callbacks, and Rails executes callbacks in order. Therefore, other
|
1114
|
+
# similar callbacks may affect the :dependent behavior, and the
|
1115
|
+
# :dependent behavior may affect other callbacks.
|
1116
|
+
#
|
1117
|
+
# * <tt>:destroy</tt> causes all the associated objects to also be destroyed
|
1118
|
+
# * <tt>:delete_all</tt> causes all the asssociated objects to be deleted directly from the database (so callbacks will not execute)
|
1119
|
+
# * <tt>:nullify</tt> causes the foreign keys to be set to +NULL+. Callbacks are not executed.
|
1120
|
+
# * <tt>:restrict_with_exception</tt> causes an exception to be raised if there are any associated records
|
1121
|
+
# * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there are any associated objects
|
1106
1122
|
#
|
1107
1123
|
# If using with the <tt>:through</tt> option, the association on the join model must be
|
1108
1124
|
# a +belongs_to+, and the records which get deleted are the join records, rather than
|
1109
1125
|
# the associated records.
|
1110
|
-
#
|
1111
|
-
#
|
1112
|
-
#
|
1113
|
-
# associations that depend on multiple tables. May be supplied as a string or a proc where interpolation is
|
1114
|
-
# required. Note: When this option is used, +find_in_collection+
|
1115
|
-
# is _not_ added.
|
1116
|
-
# [:counter_sql]
|
1117
|
-
# Specify a complete SQL statement to fetch the size of the association. If <tt>:finder_sql</tt> is
|
1118
|
-
# specified but not <tt>:counter_sql</tt>, <tt>:counter_sql</tt> will be generated by
|
1119
|
-
# replacing <tt>SELECT ... FROM</tt> with <tt>SELECT COUNT(*) FROM</tt>.
|
1120
|
-
# [:extend]
|
1121
|
-
# Specify a named module for extending the proxy. See "Association extensions".
|
1122
|
-
# [:include]
|
1123
|
-
# Specify second-order associations that should be eager loaded when the collection is loaded.
|
1124
|
-
# [:group]
|
1125
|
-
# An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
|
1126
|
-
# [:having]
|
1127
|
-
# Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt>
|
1128
|
-
# returns. Uses the <tt>HAVING</tt> SQL-clause.
|
1129
|
-
# [:limit]
|
1130
|
-
# An integer determining the limit on the number of rows that should be returned.
|
1131
|
-
# [:offset]
|
1132
|
-
# An integer determining the offset from where the rows should be fetched. So at 5,
|
1133
|
-
# it would skip the first 4 rows.
|
1134
|
-
# [:select]
|
1135
|
-
# By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if
|
1136
|
-
# you, for example, want to do a join but not include the joined columns. Do not forget
|
1137
|
-
# to include the primary and foreign keys, otherwise it will raise an error.
|
1126
|
+
# [:counter_cache]
|
1127
|
+
# This option can be used to configure a custom named <tt>:counter_cache.</tt> You only need this option,
|
1128
|
+
# when you customized the name of your <tt>:counter_cache</tt> on the <tt>belongs_to</tt> association.
|
1138
1129
|
# [:as]
|
1139
1130
|
# Specifies a polymorphic interface (See <tt>belongs_to</tt>).
|
1140
1131
|
# [:through]
|
@@ -1156,21 +1147,21 @@ module ActiveRecord
|
|
1156
1147
|
# [:source]
|
1157
1148
|
# Specifies the source association name used by <tt>has_many :through</tt> queries.
|
1158
1149
|
# Only use it if the name cannot be inferred from the association.
|
1159
|
-
# <tt>has_many :subscribers, :
|
1150
|
+
# <tt>has_many :subscribers, through: :subscriptions</tt> will look for either <tt>:subscribers</tt> or
|
1160
1151
|
# <tt>:subscriber</tt> on Subscription, unless a <tt>:source</tt> is given.
|
1161
1152
|
# [:source_type]
|
1162
1153
|
# Specifies type of the source association used by <tt>has_many :through</tt> queries where the source
|
1163
1154
|
# association is a polymorphic +belongs_to+.
|
1164
|
-
# [:uniq]
|
1165
|
-
# If true, duplicates will be omitted from the collection. Useful in conjunction with <tt>:through</tt>.
|
1166
|
-
# [:readonly]
|
1167
|
-
# If true, all the associated objects are readonly through the association.
|
1168
1155
|
# [:validate]
|
1169
1156
|
# If +false+, don't validate the associated objects when saving the parent object. true by default.
|
1170
1157
|
# [:autosave]
|
1171
1158
|
# If true, always save the associated objects or destroy them if marked for destruction,
|
1172
1159
|
# when saving the parent object. If false, never save or destroy the associated objects.
|
1173
|
-
# By default, only save associated objects that are new records.
|
1160
|
+
# By default, only save associated objects that are new records. This option is implemented as a
|
1161
|
+
# before_save callback. Because callbacks are run in the order they are defined, associated objects
|
1162
|
+
# may need to be explicitly saved in any user-defined before_save callbacks.
|
1163
|
+
#
|
1164
|
+
# Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
|
1174
1165
|
# [:inverse_of]
|
1175
1166
|
# Specifies the name of the <tt>belongs_to</tt> association on the associated object
|
1176
1167
|
# that is the inverse of this <tt>has_many</tt> association. Does not work in combination
|
@@ -1178,24 +1169,16 @@ module ActiveRecord
|
|
1178
1169
|
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
|
1179
1170
|
#
|
1180
1171
|
# Option examples:
|
1181
|
-
# has_many :comments,
|
1182
|
-
# has_many :comments,
|
1183
|
-
# has_many :people,
|
1184
|
-
# has_many :tracks,
|
1185
|
-
# has_many :comments, :
|
1186
|
-
# has_many :tags, :
|
1187
|
-
# has_many :reports,
|
1188
|
-
# has_many :subscribers, :
|
1189
|
-
|
1190
|
-
|
1191
|
-
# SELECT DISTINCT *
|
1192
|
-
# FROM people p, post_subscriptions ps
|
1193
|
-
# WHERE ps.post_id = #{id} AND ps.person_id = p.id
|
1194
|
-
# ORDER BY p.first_name
|
1195
|
-
# }
|
1196
|
-
# }
|
1197
|
-
def has_many(name, options = {}, &extension)
|
1198
|
-
Builder::HasMany.build(self, name, options, &extension)
|
1172
|
+
# has_many :comments, -> { order "posted_on" }
|
1173
|
+
# has_many :comments, -> { includes :author }
|
1174
|
+
# has_many :people, -> { where("deleted = 0").order("name") }, class_name: "Person"
|
1175
|
+
# has_many :tracks, -> { order "position" }, dependent: :destroy
|
1176
|
+
# has_many :comments, dependent: :nullify
|
1177
|
+
# has_many :tags, as: :taggable
|
1178
|
+
# has_many :reports, -> { readonly }
|
1179
|
+
# has_many :subscribers, through: :subscriptions, source: :user
|
1180
|
+
def has_many(name, scope = nil, options = {}, &extension)
|
1181
|
+
Builder::HasMany.build(self, name, scope, options, &extension)
|
1199
1182
|
end
|
1200
1183
|
|
1201
1184
|
# Specifies a one-to-one association with another class. This method should only be used
|
@@ -1228,7 +1211,7 @@ module ActiveRecord
|
|
1228
1211
|
# === Example
|
1229
1212
|
#
|
1230
1213
|
# An Account class declares <tt>has_one :beneficiary</tt>, which will add:
|
1231
|
-
# * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.
|
1214
|
+
# * <tt>Account#beneficiary</tt> (similar to <tt>Beneficiary.where(account_id: id).first</tt>)
|
1232
1215
|
# * <tt>Account#beneficiary=(beneficiary)</tt> (similar to <tt>beneficiary.account_id = account.id; beneficiary.save</tt>)
|
1233
1216
|
# * <tt>Account#build_beneficiary</tt> (similar to <tt>Beneficiary.new("account_id" => id)</tt>)
|
1234
1217
|
# * <tt>Account#create_beneficiary</tt> (similar to <tt>b = Beneficiary.new("account_id" => id); b.save; b</tt>)
|
@@ -1243,34 +1226,23 @@ module ActiveRecord
|
|
1243
1226
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
1244
1227
|
# from the association name. So <tt>has_one :manager</tt> will by default be linked to the Manager class, but
|
1245
1228
|
# if the real class name is Person, you'll have to specify it with this option.
|
1246
|
-
# [:conditions]
|
1247
|
-
# Specify the conditions that the associated object must meet in order to be included as a +WHERE+
|
1248
|
-
# SQL fragment, such as <tt>rank = 5</tt>. Record creation from the association is scoped if a hash
|
1249
|
-
# is used. <tt>has_one :account, :conditions => {:enabled => true}</tt> will create
|
1250
|
-
# an enabled account with <tt>@company.create_account</tt> or <tt>@company.build_account</tt>.
|
1251
|
-
# [:order]
|
1252
|
-
# Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
|
1253
|
-
# such as <tt>last_name, first_name DESC</tt>.
|
1254
1229
|
# [:dependent]
|
1255
|
-
#
|
1256
|
-
#
|
1257
|
-
#
|
1258
|
-
#
|
1259
|
-
# <tt
|
1230
|
+
# Controls what happens to the associated object when
|
1231
|
+
# its owner is destroyed:
|
1232
|
+
#
|
1233
|
+
# * <tt>:destroy</tt> causes the associated object to also be destroyed
|
1234
|
+
# * <tt>:delete</tt> causes the asssociated object to be deleted directly from the database (so callbacks will not execute)
|
1235
|
+
# * <tt>:nullify</tt> causes the foreign key to be set to +NULL+. Callbacks are not executed.
|
1236
|
+
# * <tt>:restrict_with_exception</tt> causes an exception to be raised if there is an associated record
|
1237
|
+
# * <tt>:restrict_with_error</tt> causes an error to be added to the owner if there is an associated object
|
1260
1238
|
# [:foreign_key]
|
1261
1239
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
1262
1240
|
# of this class in lower-case and "_id" suffixed. So a Person class that makes a +has_one+ association
|
1263
1241
|
# will use "person_id" as the default <tt>:foreign_key</tt>.
|
1264
1242
|
# [:primary_key]
|
1265
1243
|
# Specify the method that returns the primary key used for the association. By default this is +id+.
|
1266
|
-
# [:include]
|
1267
|
-
# Specify second-order associations that should be eager loaded when this object is loaded.
|
1268
1244
|
# [:as]
|
1269
1245
|
# Specifies a polymorphic interface (See <tt>belongs_to</tt>).
|
1270
|
-
# [:select]
|
1271
|
-
# By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example,
|
1272
|
-
# you want to do a join but not include the joined columns. Do not forget to include the
|
1273
|
-
# primary and foreign keys, otherwise it will raise an error.
|
1274
1246
|
# [:through]
|
1275
1247
|
# Specifies a Join Model through which to perform the query. Options for <tt>:class_name</tt>,
|
1276
1248
|
# <tt>:primary_key</tt>, and <tt>:foreign_key</tt> are ignored, as the association uses the
|
@@ -1279,19 +1251,19 @@ module ActiveRecord
|
|
1279
1251
|
# [:source]
|
1280
1252
|
# Specifies the source association name used by <tt>has_one :through</tt> queries.
|
1281
1253
|
# Only use it if the name cannot be inferred from the association.
|
1282
|
-
# <tt>has_one :favorite, :
|
1254
|
+
# <tt>has_one :favorite, through: :favorites</tt> will look for a
|
1283
1255
|
# <tt>:favorite</tt> on Favorite, unless a <tt>:source</tt> is given.
|
1284
1256
|
# [:source_type]
|
1285
1257
|
# Specifies type of the source association used by <tt>has_one :through</tt> queries where the source
|
1286
1258
|
# association is a polymorphic +belongs_to+.
|
1287
|
-
# [:readonly]
|
1288
|
-
# If true, the associated object is readonly through the association.
|
1289
1259
|
# [:validate]
|
1290
1260
|
# If +false+, don't validate the associated object when saving the parent object. +false+ by default.
|
1291
1261
|
# [:autosave]
|
1292
1262
|
# If true, always save the associated object or destroy it if marked for destruction,
|
1293
1263
|
# when saving the parent object. If false, never save or destroy the associated object.
|
1294
1264
|
# By default, only save the associated object if it's a new record.
|
1265
|
+
#
|
1266
|
+
# Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
|
1295
1267
|
# [:inverse_of]
|
1296
1268
|
# Specifies the name of the <tt>belongs_to</tt> association on the associated object
|
1297
1269
|
# that is the inverse of this <tt>has_one</tt> association. Does not work in combination
|
@@ -1299,17 +1271,17 @@ module ActiveRecord
|
|
1299
1271
|
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
|
1300
1272
|
#
|
1301
1273
|
# Option examples:
|
1302
|
-
# has_one :credit_card, :
|
1303
|
-
# has_one :credit_card, :
|
1274
|
+
# has_one :credit_card, dependent: :destroy # destroys the associated credit card
|
1275
|
+
# has_one :credit_card, dependent: :nullify # updates the associated records foreign
|
1304
1276
|
# # key value to NULL rather than destroying it
|
1305
|
-
# has_one :last_comment,
|
1306
|
-
# has_one :project_manager,
|
1307
|
-
# has_one :attachment, :
|
1308
|
-
# has_one :boss, :
|
1309
|
-
# has_one :club, :
|
1310
|
-
# has_one :primary_address,
|
1311
|
-
def has_one(name, options = {})
|
1312
|
-
Builder::HasOne.build(self, name, options)
|
1277
|
+
# has_one :last_comment, -> { order 'posted_on' }, class_name: "Comment"
|
1278
|
+
# has_one :project_manager, -> { where role: 'project_manager' }, class_name: "Person"
|
1279
|
+
# has_one :attachment, as: :attachable
|
1280
|
+
# has_one :boss, readonly: :true
|
1281
|
+
# has_one :club, through: :membership
|
1282
|
+
# has_one :primary_address, -> { where primary: true }, through: :addressables, source: :addressable
|
1283
|
+
def has_one(name, scope = nil, options = {})
|
1284
|
+
Builder::HasOne.build(self, name, scope, options)
|
1313
1285
|
end
|
1314
1286
|
|
1315
1287
|
# Specifies a one-to-one association with another class. This method should only be used
|
@@ -1354,23 +1326,16 @@ module ActiveRecord
|
|
1354
1326
|
# Specify the class name of the association. Use it only if that name can't be inferred
|
1355
1327
|
# from the association name. So <tt>belongs_to :author</tt> will by default be linked to the Author class, but
|
1356
1328
|
# if the real class name is Person, you'll have to specify it with this option.
|
1357
|
-
# [:conditions]
|
1358
|
-
# Specify the conditions that the associated object must meet in order to be included as a +WHERE+
|
1359
|
-
# SQL fragment, such as <tt>authorized = 1</tt>.
|
1360
|
-
# [:select]
|
1361
|
-
# By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed
|
1362
|
-
# if, for example, you want to do a join but not include the joined columns. Do not
|
1363
|
-
# forget to include the primary and foreign keys, otherwise it will raise an error.
|
1364
1329
|
# [:foreign_key]
|
1365
1330
|
# Specify the foreign key used for the association. By default this is guessed to be the name
|
1366
1331
|
# of the association with an "_id" suffix. So a class that defines a <tt>belongs_to :person</tt>
|
1367
1332
|
# association will use "person_id" as the default <tt>:foreign_key</tt>. Similarly,
|
1368
|
-
# <tt>belongs_to :favorite_person, :
|
1333
|
+
# <tt>belongs_to :favorite_person, class_name: "Person"</tt> will use a foreign key
|
1369
1334
|
# of "favorite_person_id".
|
1370
1335
|
# [:foreign_type]
|
1371
1336
|
# Specify the column used to store the associated object's type, if this is a polymorphic
|
1372
1337
|
# association. By default this is guessed to be the name of the association with a "_type"
|
1373
|
-
# suffix. So a class that defines a <tt>belongs_to :taggable, :
|
1338
|
+
# suffix. So a class that defines a <tt>belongs_to :taggable, polymorphic: true</tt>
|
1374
1339
|
# association will use "taggable_type" as the default <tt>:foreign_type</tt>.
|
1375
1340
|
# [:primary_key]
|
1376
1341
|
# Specify the method that returns the primary key of associated object used for the association.
|
@@ -1386,19 +1351,17 @@ module ActiveRecord
|
|
1386
1351
|
# and +decrement_counter+. The counter cache is incremented when an object of this
|
1387
1352
|
# class is created and decremented when it's destroyed. This requires that a column
|
1388
1353
|
# named <tt>#{table_name}_count</tt> (such as +comments_count+ for a belonging Comment class)
|
1389
|
-
# is used on the associate class (such as a Post class)
|
1354
|
+
# is used on the associate class (such as a Post class) - that is the migration for
|
1355
|
+
# <tt>#{table_name}_count</tt> is created on the associate class (such that Post.comments_count will
|
1356
|
+
# return the count cached, see note below). You can also specify a custom counter
|
1390
1357
|
# cache column by providing a column name instead of a +true+/+false+ value to this
|
1391
|
-
# option (e.g., <tt
|
1358
|
+
# option (e.g., <tt>counter_cache: :my_custom_counter</tt>.)
|
1392
1359
|
# Note: Specifying a counter cache will add it to that model's list of readonly attributes
|
1393
1360
|
# using +attr_readonly+.
|
1394
|
-
# [:include]
|
1395
|
-
# Specify second-order associations that should be eager loaded when this object is loaded.
|
1396
1361
|
# [:polymorphic]
|
1397
1362
|
# Specify this association is a polymorphic association by passing +true+.
|
1398
1363
|
# Note: If you've enabled the counter cache, then you may want to add the counter cache attribute
|
1399
1364
|
# to the +attr_readonly+ list in the associated classes (e.g. <tt>class Post; attr_readonly :comments_count; end</tt>).
|
1400
|
-
# [:readonly]
|
1401
|
-
# If true, the associated object is readonly through the association.
|
1402
1365
|
# [:validate]
|
1403
1366
|
# If +false+, don't validate the associated objects when saving the parent object. +false+ by default.
|
1404
1367
|
# [:autosave]
|
@@ -1406,6 +1369,8 @@ module ActiveRecord
|
|
1406
1369
|
# saving the parent object.
|
1407
1370
|
# If false, never save or destroy the associated object.
|
1408
1371
|
# By default, only save the associated object if it's a new record.
|
1372
|
+
#
|
1373
|
+
# Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
|
1409
1374
|
# [:touch]
|
1410
1375
|
# If true, the associated object will be touched (the updated_at/on attributes set to now)
|
1411
1376
|
# when this record is either saved or destroyed. If you specify a symbol, that attribute
|
@@ -1417,24 +1382,24 @@ module ActiveRecord
|
|
1417
1382
|
# See ActiveRecord::Associations::ClassMethods's overview on Bi-directional associations for more detail.
|
1418
1383
|
#
|
1419
1384
|
# Option examples:
|
1420
|
-
# belongs_to :firm, :
|
1421
|
-
# belongs_to :person, :
|
1422
|
-
# belongs_to :author, :
|
1423
|
-
# belongs_to :valid_coupon,
|
1424
|
-
#
|
1425
|
-
# belongs_to :attachable, :
|
1426
|
-
# belongs_to :project, :
|
1427
|
-
# belongs_to :post, :
|
1428
|
-
# belongs_to :company, :
|
1429
|
-
# belongs_to :company, :
|
1430
|
-
def belongs_to(name, options = {})
|
1431
|
-
Builder::BelongsTo.build(self, name, options)
|
1385
|
+
# belongs_to :firm, foreign_key: "client_of"
|
1386
|
+
# belongs_to :person, primary_key: "name", foreign_key: "person_name"
|
1387
|
+
# belongs_to :author, class_name: "Person", foreign_key: "author_id"
|
1388
|
+
# belongs_to :valid_coupon, ->(o) { where "discounts > #{o.payments_count}" },
|
1389
|
+
# class_name: "Coupon", foreign_key: "coupon_id"
|
1390
|
+
# belongs_to :attachable, polymorphic: true
|
1391
|
+
# belongs_to :project, readonly: true
|
1392
|
+
# belongs_to :post, counter_cache: true
|
1393
|
+
# belongs_to :company, touch: true
|
1394
|
+
# belongs_to :company, touch: :employees_last_updated_at
|
1395
|
+
def belongs_to(name, scope = nil, options = {})
|
1396
|
+
Builder::BelongsTo.build(self, name, scope, options)
|
1432
1397
|
end
|
1433
1398
|
|
1434
1399
|
# Specifies a many-to-many relationship with another class. This associates two classes via an
|
1435
1400
|
# intermediate join table. Unless the join table is explicitly specified as an option, it is
|
1436
1401
|
# guessed using the lexical order of the class names. So a join between Developer and Project
|
1437
|
-
# will give the default join table name of "developers_projects" because "D"
|
1402
|
+
# will give the default join table name of "developers_projects" because "D" precedes "P" alphabetically.
|
1438
1403
|
# Note that this precedence is calculated using the <tt><</tt> operator for String. This
|
1439
1404
|
# means that if the strings are of different lengths, and the strings are equal when compared
|
1440
1405
|
# up to the shortest length, then the longer string is considered of higher
|
@@ -1448,7 +1413,7 @@ module ActiveRecord
|
|
1448
1413
|
#
|
1449
1414
|
# class CreateDevelopersProjectsJoinTable < ActiveRecord::Migration
|
1450
1415
|
# def change
|
1451
|
-
# create_table :developers_projects, :
|
1416
|
+
# create_table :developers_projects, id: false do |t|
|
1452
1417
|
# t.integer :developer_id
|
1453
1418
|
# t.integer :project_id
|
1454
1419
|
# end
|
@@ -1472,6 +1437,9 @@ module ActiveRecord
|
|
1472
1437
|
# [collection.delete(object, ...)]
|
1473
1438
|
# Removes one or more objects from the collection by removing their associations from the join table.
|
1474
1439
|
# This does not destroy the objects.
|
1440
|
+
# [collection.destroy(object, ...)]
|
1441
|
+
# Removes one or more objects from the collection by running destroy on each association in the join table, overriding any dependent option.
|
1442
|
+
# This does not destroy the objects.
|
1475
1443
|
# [collection=objects]
|
1476
1444
|
# Replaces the collection's content by deleting and adding objects as appropriate.
|
1477
1445
|
# [collection_singular_ids]
|
@@ -1508,6 +1476,7 @@ module ActiveRecord
|
|
1508
1476
|
# * <tt>Developer#projects</tt>
|
1509
1477
|
# * <tt>Developer#projects<<</tt>
|
1510
1478
|
# * <tt>Developer#projects.delete</tt>
|
1479
|
+
# * <tt>Developer#projects.destroy</tt>
|
1511
1480
|
# * <tt>Developer#projects=</tt>
|
1512
1481
|
# * <tt>Developer#project_ids</tt>
|
1513
1482
|
# * <tt>Developer#project_ids=</tt>
|
@@ -1540,47 +1509,6 @@ module ActiveRecord
|
|
1540
1509
|
# By default this is guessed to be the name of the associated class in lower-case and "_id" suffixed.
|
1541
1510
|
# So if a Person class makes a +has_and_belongs_to_many+ association to Project,
|
1542
1511
|
# the association will use "project_id" as the default <tt>:association_foreign_key</tt>.
|
1543
|
-
# [:conditions]
|
1544
|
-
# Specify the conditions that the associated object must meet in order to be included as a +WHERE+
|
1545
|
-
# SQL fragment, such as <tt>authorized = 1</tt>. Record creations from the association are
|
1546
|
-
# scoped if a hash is used.
|
1547
|
-
# <tt>has_many :posts, :conditions => {:published => true}</tt> will create published posts with <tt>@blog.posts.create</tt>
|
1548
|
-
# or <tt>@blog.posts.build</tt>.
|
1549
|
-
# [:order]
|
1550
|
-
# Specify the order in which the associated objects are returned as an <tt>ORDER BY</tt> SQL fragment,
|
1551
|
-
# such as <tt>last_name, first_name DESC</tt>
|
1552
|
-
# [:uniq]
|
1553
|
-
# If true, duplicate associated objects will be ignored by accessors and query methods.
|
1554
|
-
# [:finder_sql]
|
1555
|
-
# Overwrite the default generated SQL statement used to fetch the association with a manual statement
|
1556
|
-
# [:counter_sql]
|
1557
|
-
# Specify a complete SQL statement to fetch the size of the association. If <tt>:finder_sql</tt> is
|
1558
|
-
# specified but not <tt>:counter_sql</tt>, <tt>:counter_sql</tt> will be generated by
|
1559
|
-
# replacing <tt>SELECT ... FROM</tt> with <tt>SELECT COUNT(*) FROM</tt>.
|
1560
|
-
# [:delete_sql]
|
1561
|
-
# Overwrite the default generated SQL statement used to remove links between the associated
|
1562
|
-
# classes with a manual statement.
|
1563
|
-
# [:insert_sql]
|
1564
|
-
# Overwrite the default generated SQL statement used to add links between the associated classes
|
1565
|
-
# with a manual statement.
|
1566
|
-
# [:extend]
|
1567
|
-
# Anonymous module for extending the proxy, see "Association extensions".
|
1568
|
-
# [:include]
|
1569
|
-
# Specify second-order associations that should be eager loaded when the collection is loaded.
|
1570
|
-
# [:group]
|
1571
|
-
# An attribute name by which the result should be grouped. Uses the <tt>GROUP BY</tt> SQL-clause.
|
1572
|
-
# [:having]
|
1573
|
-
# Combined with +:group+ this can be used to filter the records that a <tt>GROUP BY</tt> returns.
|
1574
|
-
# Uses the <tt>HAVING</tt> SQL-clause.
|
1575
|
-
# [:limit]
|
1576
|
-
# An integer determining the limit on the number of rows that should be returned.
|
1577
|
-
# [:offset]
|
1578
|
-
# An integer determining the offset from where the rows should be fetched. So at 5,
|
1579
|
-
# it would skip the first 4 rows.
|
1580
|
-
# [:select]
|
1581
|
-
# By default, this is <tt>*</tt> as in <tt>SELECT * FROM</tt>, but can be changed if, for example,
|
1582
|
-
# you want to do a join but not include the joined columns. Do not forget to include the primary
|
1583
|
-
# and foreign keys, otherwise it will raise an error.
|
1584
1512
|
# [:readonly]
|
1585
1513
|
# If true, all the associated objects are readonly through the association.
|
1586
1514
|
# [:validate]
|
@@ -1591,16 +1519,16 @@ module ActiveRecord
|
|
1591
1519
|
# If false, never save or destroy the associated objects.
|
1592
1520
|
# By default, only save associated objects that are new records.
|
1593
1521
|
#
|
1522
|
+
# Note that <tt>accepts_nested_attributes_for</tt> sets <tt>:autosave</tt> to <tt>true</tt>.
|
1523
|
+
#
|
1594
1524
|
# Option examples:
|
1595
1525
|
# has_and_belongs_to_many :projects
|
1596
|
-
# has_and_belongs_to_many :projects,
|
1597
|
-
# has_and_belongs_to_many :nations, :
|
1598
|
-
# has_and_belongs_to_many :categories, :
|
1599
|
-
# has_and_belongs_to_many :categories,
|
1600
|
-
|
1601
|
-
|
1602
|
-
def has_and_belongs_to_many(name, options = {}, &extension)
|
1603
|
-
Builder::HasAndBelongsToMany.build(self, name, options, &extension)
|
1526
|
+
# has_and_belongs_to_many :projects, -> { includes :milestones, :manager }
|
1527
|
+
# has_and_belongs_to_many :nations, class_name: "Country"
|
1528
|
+
# has_and_belongs_to_many :categories, join_table: "prods_cats"
|
1529
|
+
# has_and_belongs_to_many :categories, -> { readonly }
|
1530
|
+
def has_and_belongs_to_many(name, scope = nil, options = {}, &extension)
|
1531
|
+
Builder::HasAndBelongsToMany.build(self, name, scope, options, &extension)
|
1604
1532
|
end
|
1605
1533
|
end
|
1606
1534
|
end
|