square-activerecord 3.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +6140 -0
- data/README.rdoc +222 -0
- data/examples/associations.png +0 -0
- data/examples/performance.rb +179 -0
- data/examples/simple.rb +14 -0
- data/lib/active_record.rb +124 -0
- data/lib/active_record/aggregations.rb +277 -0
- data/lib/active_record/association_preload.rb +430 -0
- data/lib/active_record/associations.rb +2307 -0
- data/lib/active_record/associations/association_collection.rb +572 -0
- data/lib/active_record/associations/association_proxy.rb +299 -0
- data/lib/active_record/associations/belongs_to_association.rb +91 -0
- data/lib/active_record/associations/belongs_to_polymorphic_association.rb +82 -0
- data/lib/active_record/associations/has_and_belongs_to_many_association.rb +143 -0
- data/lib/active_record/associations/has_many_association.rb +128 -0
- data/lib/active_record/associations/has_many_through_association.rb +115 -0
- data/lib/active_record/associations/has_one_association.rb +143 -0
- data/lib/active_record/associations/has_one_through_association.rb +40 -0
- data/lib/active_record/associations/through_association_scope.rb +154 -0
- data/lib/active_record/attribute_methods.rb +60 -0
- data/lib/active_record/attribute_methods/before_type_cast.rb +30 -0
- data/lib/active_record/attribute_methods/dirty.rb +95 -0
- data/lib/active_record/attribute_methods/primary_key.rb +56 -0
- data/lib/active_record/attribute_methods/query.rb +39 -0
- data/lib/active_record/attribute_methods/read.rb +145 -0
- data/lib/active_record/attribute_methods/time_zone_conversion.rb +64 -0
- data/lib/active_record/attribute_methods/write.rb +43 -0
- data/lib/active_record/autosave_association.rb +369 -0
- data/lib/active_record/base.rb +1904 -0
- data/lib/active_record/callbacks.rb +284 -0
- data/lib/active_record/connection_adapters/abstract/connection_pool.rb +364 -0
- data/lib/active_record/connection_adapters/abstract/connection_specification.rb +113 -0
- data/lib/active_record/connection_adapters/abstract/database_limits.rb +57 -0
- data/lib/active_record/connection_adapters/abstract/database_statements.rb +333 -0
- data/lib/active_record/connection_adapters/abstract/query_cache.rb +81 -0
- data/lib/active_record/connection_adapters/abstract/quoting.rb +73 -0
- data/lib/active_record/connection_adapters/abstract/schema_definitions.rb +739 -0
- data/lib/active_record/connection_adapters/abstract/schema_statements.rb +539 -0
- data/lib/active_record/connection_adapters/abstract_adapter.rb +217 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +657 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1031 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +61 -0
- data/lib/active_record/connection_adapters/sqlite_adapter.rb +401 -0
- data/lib/active_record/counter_cache.rb +115 -0
- data/lib/active_record/dynamic_finder_match.rb +56 -0
- data/lib/active_record/dynamic_scope_match.rb +23 -0
- data/lib/active_record/errors.rb +172 -0
- data/lib/active_record/fixtures.rb +1006 -0
- data/lib/active_record/locale/en.yml +40 -0
- data/lib/active_record/locking/optimistic.rb +172 -0
- data/lib/active_record/locking/pessimistic.rb +55 -0
- data/lib/active_record/log_subscriber.rb +48 -0
- data/lib/active_record/migration.rb +617 -0
- data/lib/active_record/named_scope.rb +138 -0
- data/lib/active_record/nested_attributes.rb +419 -0
- data/lib/active_record/observer.rb +125 -0
- data/lib/active_record/persistence.rb +290 -0
- data/lib/active_record/query_cache.rb +36 -0
- data/lib/active_record/railtie.rb +91 -0
- data/lib/active_record/railties/controller_runtime.rb +38 -0
- data/lib/active_record/railties/databases.rake +512 -0
- data/lib/active_record/reflection.rb +411 -0
- data/lib/active_record/relation.rb +394 -0
- data/lib/active_record/relation/batches.rb +89 -0
- data/lib/active_record/relation/calculations.rb +295 -0
- data/lib/active_record/relation/finder_methods.rb +363 -0
- data/lib/active_record/relation/predicate_builder.rb +48 -0
- data/lib/active_record/relation/query_methods.rb +303 -0
- data/lib/active_record/relation/spawn_methods.rb +132 -0
- data/lib/active_record/schema.rb +59 -0
- data/lib/active_record/schema_dumper.rb +195 -0
- data/lib/active_record/serialization.rb +60 -0
- data/lib/active_record/serializers/xml_serializer.rb +244 -0
- data/lib/active_record/session_store.rb +340 -0
- data/lib/active_record/test_case.rb +67 -0
- data/lib/active_record/timestamp.rb +88 -0
- data/lib/active_record/transactions.rb +359 -0
- data/lib/active_record/validations.rb +84 -0
- data/lib/active_record/validations/associated.rb +48 -0
- data/lib/active_record/validations/uniqueness.rb +190 -0
- data/lib/active_record/version.rb +10 -0
- data/lib/rails/generators/active_record.rb +19 -0
- data/lib/rails/generators/active_record/migration.rb +15 -0
- data/lib/rails/generators/active_record/migration/migration_generator.rb +25 -0
- data/lib/rails/generators/active_record/migration/templates/migration.rb +17 -0
- data/lib/rails/generators/active_record/model/model_generator.rb +38 -0
- data/lib/rails/generators/active_record/model/templates/migration.rb +16 -0
- data/lib/rails/generators/active_record/model/templates/model.rb +5 -0
- data/lib/rails/generators/active_record/model/templates/module.rb +5 -0
- data/lib/rails/generators/active_record/observer/observer_generator.rb +15 -0
- data/lib/rails/generators/active_record/observer/templates/observer.rb +2 -0
- data/lib/rails/generators/active_record/session_migration/session_migration_generator.rb +24 -0
- data/lib/rails/generators/active_record/session_migration/templates/migration.rb +16 -0
- metadata +223 -0
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
# = Active Record Observer
|
5
|
+
#
|
6
|
+
# Observer classes respond to life cycle callbacks to implement trigger-like
|
7
|
+
# behavior outside the original class. This is a great way to reduce the
|
8
|
+
# clutter that normally comes when the model class is burdened with
|
9
|
+
# functionality that doesn't pertain to the core responsibility of the
|
10
|
+
# class. Example:
|
11
|
+
#
|
12
|
+
# class CommentObserver < ActiveRecord::Observer
|
13
|
+
# def after_save(comment)
|
14
|
+
# Notifications.deliver_comment("admin@do.com", "New comment was posted", comment)
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# This Observer sends an email when a Comment#save is finished.
|
19
|
+
#
|
20
|
+
# class ContactObserver < ActiveRecord::Observer
|
21
|
+
# def after_create(contact)
|
22
|
+
# contact.logger.info('New contact added!')
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# def after_destroy(contact)
|
26
|
+
# contact.logger.warn("Contact with an id of #{contact.id} was destroyed!")
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# This Observer uses logger to log when specific callbacks are triggered.
|
31
|
+
#
|
32
|
+
# == Observing a class that can't be inferred
|
33
|
+
#
|
34
|
+
# Observers will by default be mapped to the class with which they share a name. So CommentObserver will
|
35
|
+
# be tied to observing Comment, ProductManagerObserver to ProductManager, and so on. If you want to name your observer
|
36
|
+
# differently than the class you're interested in observing, you can use the Observer.observe class method which takes
|
37
|
+
# either the concrete class (Product) or a symbol for that class (:product):
|
38
|
+
#
|
39
|
+
# class AuditObserver < ActiveRecord::Observer
|
40
|
+
# observe :account
|
41
|
+
#
|
42
|
+
# def after_update(account)
|
43
|
+
# AuditTrail.new(account, "UPDATED")
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# If the audit observer needs to watch more than one kind of object, this can be specified with multiple arguments:
|
48
|
+
#
|
49
|
+
# class AuditObserver < ActiveRecord::Observer
|
50
|
+
# observe :account, :balance
|
51
|
+
#
|
52
|
+
# def after_update(record)
|
53
|
+
# AuditTrail.new(record, "UPDATED")
|
54
|
+
# end
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# The AuditObserver will now act on both updates to Account and Balance by treating them both as records.
|
58
|
+
#
|
59
|
+
# == Available callback methods
|
60
|
+
#
|
61
|
+
# The observer can implement callback methods for each of the methods described in the Callbacks module.
|
62
|
+
#
|
63
|
+
# == Storing Observers in Rails
|
64
|
+
#
|
65
|
+
# If you're using Active Record within Rails, observer classes are usually stored in app/models with the
|
66
|
+
# naming convention of app/models/audit_observer.rb.
|
67
|
+
#
|
68
|
+
# == Configuration
|
69
|
+
#
|
70
|
+
# In order to activate an observer, list it in the <tt>config.active_record.observers</tt> configuration
|
71
|
+
# setting in your <tt>config/application.rb</tt> file.
|
72
|
+
#
|
73
|
+
# config.active_record.observers = :comment_observer, :signup_observer
|
74
|
+
#
|
75
|
+
# Observers will not be invoked unless you define these in your application configuration.
|
76
|
+
#
|
77
|
+
# == Loading
|
78
|
+
#
|
79
|
+
# Observers register themselves in the model class they observe, since it is the class that
|
80
|
+
# notifies them of events when they occur. As a side-effect, when an observer is loaded its
|
81
|
+
# corresponding model class is loaded.
|
82
|
+
#
|
83
|
+
# Up to (and including) Rails 2.0.2 observers were instantiated between plugins and
|
84
|
+
# application initializers. Now observers are loaded after application initializers,
|
85
|
+
# so observed models can make use of extensions.
|
86
|
+
#
|
87
|
+
# If by any chance you are using observed models in the initialization you can still
|
88
|
+
# load their observers by calling <tt>ModelObserver.instance</tt> before. Observers are
|
89
|
+
# singletons and that call instantiates and registers them.
|
90
|
+
#
|
91
|
+
class Observer < ActiveModel::Observer
|
92
|
+
|
93
|
+
def initialize
|
94
|
+
super
|
95
|
+
observed_descendants.each { |klass| add_observer!(klass) }
|
96
|
+
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
def observed_descendants
|
101
|
+
observed_classes.sum([]) { |klass| klass.descendants }
|
102
|
+
end
|
103
|
+
|
104
|
+
def add_observer!(klass)
|
105
|
+
super
|
106
|
+
define_callbacks klass
|
107
|
+
end
|
108
|
+
|
109
|
+
def define_callbacks(klass)
|
110
|
+
observer = self
|
111
|
+
observer_name = observer.class.name.underscore.gsub('/', '__')
|
112
|
+
|
113
|
+
ActiveRecord::Callbacks::CALLBACKS.each do |callback|
|
114
|
+
next unless respond_to?(callback)
|
115
|
+
callback_meth = :"_notify_#{observer_name}_for_#{callback}"
|
116
|
+
unless klass.respond_to?(callback_meth)
|
117
|
+
klass.send(:define_method, callback_meth) do
|
118
|
+
observer.send(callback, self)
|
119
|
+
end
|
120
|
+
klass.send(callback, callback_meth)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,290 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
# = Active Record Persistence
|
3
|
+
module Persistence
|
4
|
+
# Returns true if this object hasn't been saved yet -- that is, a record
|
5
|
+
# for the object doesn't exist in the data store yet; otherwise, returns false.
|
6
|
+
def new_record?
|
7
|
+
@new_record
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns true if this object has been destroyed, otherwise returns false.
|
11
|
+
def destroyed?
|
12
|
+
@destroyed
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns if the record is persisted, i.e. it's not a new record and it was
|
16
|
+
# not destroyed.
|
17
|
+
def persisted?
|
18
|
+
!(new_record? || destroyed?)
|
19
|
+
end
|
20
|
+
|
21
|
+
# :call-seq:
|
22
|
+
# save(options)
|
23
|
+
#
|
24
|
+
# Saves the model.
|
25
|
+
#
|
26
|
+
# If the model is new a record gets created in the database, otherwise
|
27
|
+
# the existing record gets updated.
|
28
|
+
#
|
29
|
+
# By default, save always run validations. If any of them fail the action
|
30
|
+
# is cancelled and +save+ returns +false+. However, if you supply
|
31
|
+
# :validate => false, validations are bypassed altogether. See
|
32
|
+
# ActiveRecord::Validations for more information.
|
33
|
+
#
|
34
|
+
# There's a series of callbacks associated with +save+. If any of the
|
35
|
+
# <tt>before_*</tt> callbacks return +false+ the action is cancelled and
|
36
|
+
# +save+ returns +false+. See ActiveRecord::Callbacks for further
|
37
|
+
# details.
|
38
|
+
def save(*)
|
39
|
+
create_or_update
|
40
|
+
end
|
41
|
+
|
42
|
+
# Saves the model.
|
43
|
+
#
|
44
|
+
# If the model is new a record gets created in the database, otherwise
|
45
|
+
# the existing record gets updated.
|
46
|
+
#
|
47
|
+
# With <tt>save!</tt> validations always run. If any of them fail
|
48
|
+
# ActiveRecord::RecordInvalid gets raised. See ActiveRecord::Validations
|
49
|
+
# for more information.
|
50
|
+
#
|
51
|
+
# There's a series of callbacks associated with <tt>save!</tt>. If any of
|
52
|
+
# the <tt>before_*</tt> callbacks return +false+ the action is cancelled
|
53
|
+
# and <tt>save!</tt> raises ActiveRecord::RecordNotSaved. See
|
54
|
+
# ActiveRecord::Callbacks for further details.
|
55
|
+
def save!(*)
|
56
|
+
create_or_update || raise(RecordNotSaved)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Deletes the record in the database and freezes this instance to
|
60
|
+
# reflect that no changes should be made (since they can't be
|
61
|
+
# persisted). Returns the frozen instance.
|
62
|
+
#
|
63
|
+
# The row is simply removed with an SQL +DELETE+ statement on the
|
64
|
+
# record's primary key, and no callbacks are executed.
|
65
|
+
#
|
66
|
+
# To enforce the object's +before_destroy+ and +after_destroy+
|
67
|
+
# callbacks, Observer methods, or any <tt>:dependent</tt> association
|
68
|
+
# options, use <tt>#destroy</tt>.
|
69
|
+
def delete
|
70
|
+
self.class.delete(id) if persisted?
|
71
|
+
@destroyed = true
|
72
|
+
freeze
|
73
|
+
end
|
74
|
+
|
75
|
+
# Deletes the record in the database and freezes this instance to reflect
|
76
|
+
# that no changes should be made (since they can't be persisted).
|
77
|
+
def destroy
|
78
|
+
if persisted?
|
79
|
+
self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).delete_all
|
80
|
+
end
|
81
|
+
|
82
|
+
@destroyed = true
|
83
|
+
freeze
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns an instance of the specified +klass+ with the attributes of the
|
87
|
+
# current record. This is mostly useful in relation to single-table
|
88
|
+
# inheritance structures where you want a subclass to appear as the
|
89
|
+
# superclass. This can be used along with record identification in
|
90
|
+
# Action Pack to allow, say, <tt>Client < Company</tt> to do something
|
91
|
+
# like render <tt>:partial => @client.becomes(Company)</tt> to render that
|
92
|
+
# instance using the companies/company partial instead of clients/client.
|
93
|
+
#
|
94
|
+
# Note: The new instance will share a link to the same attributes as the original class.
|
95
|
+
# So any change to the attributes in either instance will affect the other.
|
96
|
+
def becomes(klass)
|
97
|
+
became = klass.new
|
98
|
+
became.instance_variable_set("@attributes", @attributes)
|
99
|
+
became.instance_variable_set("@attributes_cache", @attributes_cache)
|
100
|
+
became.instance_variable_set("@new_record", new_record?)
|
101
|
+
became.instance_variable_set("@destroyed", destroyed?)
|
102
|
+
became
|
103
|
+
end
|
104
|
+
|
105
|
+
# Updates a single attribute and saves the record.
|
106
|
+
# This is especially useful for boolean flags on existing records. Also note that
|
107
|
+
#
|
108
|
+
# * Validation is skipped.
|
109
|
+
# * Callbacks are invoked.
|
110
|
+
# * updated_at/updated_on column is updated if that column is available.
|
111
|
+
# * Updates all the attributes that are dirty in this object.
|
112
|
+
#
|
113
|
+
def update_attribute(name, value)
|
114
|
+
name = name.to_s
|
115
|
+
raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
|
116
|
+
send("#{name}=", value)
|
117
|
+
save(:validate => false)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Updates the attributes of the model from the passed-in hash and saves the
|
121
|
+
# record, all wrapped in a transaction. If the object is invalid, the saving
|
122
|
+
# will fail and false will be returned.
|
123
|
+
def update_attributes(attributes)
|
124
|
+
# The following transaction covers any possible database side-effects of the
|
125
|
+
# attributes assignment. For example, setting the IDs of a child collection.
|
126
|
+
with_transaction_returning_status do
|
127
|
+
self.attributes = attributes
|
128
|
+
save
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Updates its receiver just like +update_attributes+ but calls <tt>save!</tt> instead
|
133
|
+
# of +save+, so an exception is raised if the record is invalid.
|
134
|
+
def update_attributes!(attributes)
|
135
|
+
# The following transaction covers any possible database side-effects of the
|
136
|
+
# attributes assignment. For example, setting the IDs of a child collection.
|
137
|
+
with_transaction_returning_status do
|
138
|
+
self.attributes = attributes
|
139
|
+
save!
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# Initializes +attribute+ to zero if +nil+ and adds the value passed as +by+ (default is 1).
|
144
|
+
# The increment is performed directly on the underlying attribute, no setter is invoked.
|
145
|
+
# Only makes sense for number-based attributes. Returns +self+.
|
146
|
+
def increment(attribute, by = 1)
|
147
|
+
self[attribute] ||= 0
|
148
|
+
self[attribute] += by
|
149
|
+
self
|
150
|
+
end
|
151
|
+
|
152
|
+
# Wrapper around +increment+ that saves the record. This method differs from
|
153
|
+
# its non-bang version in that it passes through the attribute setter.
|
154
|
+
# Saving is not subjected to validation checks. Returns +true+ if the
|
155
|
+
# record could be saved.
|
156
|
+
def increment!(attribute, by = 1)
|
157
|
+
increment(attribute, by).update_attribute(attribute, self[attribute])
|
158
|
+
end
|
159
|
+
|
160
|
+
# Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
|
161
|
+
# The decrement is performed directly on the underlying attribute, no setter is invoked.
|
162
|
+
# Only makes sense for number-based attributes. Returns +self+.
|
163
|
+
def decrement(attribute, by = 1)
|
164
|
+
self[attribute] ||= 0
|
165
|
+
self[attribute] -= by
|
166
|
+
self
|
167
|
+
end
|
168
|
+
|
169
|
+
# Wrapper around +decrement+ that saves the record. This method differs from
|
170
|
+
# its non-bang version in that it passes through the attribute setter.
|
171
|
+
# Saving is not subjected to validation checks. Returns +true+ if the
|
172
|
+
# record could be saved.
|
173
|
+
def decrement!(attribute, by = 1)
|
174
|
+
decrement(attribute, by).update_attribute(attribute, self[attribute])
|
175
|
+
end
|
176
|
+
|
177
|
+
# Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
|
178
|
+
# if the predicate returns +true+ the attribute will become +false+. This
|
179
|
+
# method toggles directly the underlying value without calling any setter.
|
180
|
+
# Returns +self+.
|
181
|
+
def toggle(attribute)
|
182
|
+
self[attribute] = !send("#{attribute}?")
|
183
|
+
self
|
184
|
+
end
|
185
|
+
|
186
|
+
# Wrapper around +toggle+ that saves the record. This method differs from
|
187
|
+
# its non-bang version in that it passes through the attribute setter.
|
188
|
+
# Saving is not subjected to validation checks. Returns +true+ if the
|
189
|
+
# record could be saved.
|
190
|
+
def toggle!(attribute)
|
191
|
+
toggle(attribute).update_attribute(attribute, self[attribute])
|
192
|
+
end
|
193
|
+
|
194
|
+
# Reloads the attributes of this object from the database.
|
195
|
+
# The optional options argument is passed to find when reloading so you
|
196
|
+
# may do e.g. record.reload(:lock => true) to reload the same record with
|
197
|
+
# an exclusive row lock.
|
198
|
+
def reload(options = nil)
|
199
|
+
clear_aggregation_cache
|
200
|
+
clear_association_cache
|
201
|
+
@attributes.update(self.class.unscoped { self.class.find(self.id, options) }.instance_variable_get('@attributes'))
|
202
|
+
@attributes_cache = {}
|
203
|
+
self
|
204
|
+
end
|
205
|
+
|
206
|
+
# Saves the record with the updated_at/on attributes set to the current time.
|
207
|
+
# Please note that no validation is performed and no callbacks are executed.
|
208
|
+
# If an attribute name is passed, that attribute is updated along with
|
209
|
+
# updated_at/on attributes.
|
210
|
+
#
|
211
|
+
# product.touch # updates updated_at/on
|
212
|
+
# product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
|
213
|
+
#
|
214
|
+
# If used along with +belongs_to+ then +touch+ will invoke +touch+ method on associated object.
|
215
|
+
#
|
216
|
+
# class Brake < ActiveRecord::Base
|
217
|
+
# belongs_to :car, :touch => true
|
218
|
+
# end
|
219
|
+
#
|
220
|
+
# class Car < ActiveRecord::Base
|
221
|
+
# belongs_to :corporation, :touch => true
|
222
|
+
# end
|
223
|
+
#
|
224
|
+
# # triggers @brake.car.touch and @brake.car.corporation.touch
|
225
|
+
# @brake.touch
|
226
|
+
def touch(name = nil)
|
227
|
+
attributes = timestamp_attributes_for_update_in_model
|
228
|
+
attributes << name if name
|
229
|
+
unless attributes.empty?
|
230
|
+
current_time = current_time_from_proper_timezone
|
231
|
+
changes = {}
|
232
|
+
|
233
|
+
attributes.each do |column|
|
234
|
+
changes[column.to_s] = write_attribute(column.to_s, current_time)
|
235
|
+
end
|
236
|
+
|
237
|
+
@changed_attributes.except!(*changes.keys)
|
238
|
+
primary_key = self.class.primary_key
|
239
|
+
self.class.update_all(changes, { primary_key => self[primary_key] }) == 1
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
private
|
244
|
+
def create_or_update
|
245
|
+
raise ReadOnlyRecord if readonly?
|
246
|
+
result = new_record? ? create : update
|
247
|
+
result != false
|
248
|
+
end
|
249
|
+
|
250
|
+
# Updates the associated record with values matching those of the instance attributes.
|
251
|
+
# Returns the number of affected rows.
|
252
|
+
def update(attribute_names = @attributes.keys)
|
253
|
+
attributes_with_values = arel_attributes_values(false, false, attribute_names)
|
254
|
+
return 0 if attributes_with_values.empty?
|
255
|
+
self.class.unscoped.where(self.class.arel_table[self.class.primary_key].eq(id)).arel.update(attributes_with_values)
|
256
|
+
end
|
257
|
+
|
258
|
+
# Creates a record with values matching those of the instance attributes
|
259
|
+
# and returns its id.
|
260
|
+
def create
|
261
|
+
if self.id.nil? && connection.prefetch_primary_key?(self.class.table_name)
|
262
|
+
self.id = connection.next_sequence_value(self.class.sequence_name)
|
263
|
+
end
|
264
|
+
|
265
|
+
attributes_values = arel_attributes_values
|
266
|
+
|
267
|
+
new_id = if attributes_values.empty?
|
268
|
+
self.class.unscoped.insert connection.empty_insert_statement_value
|
269
|
+
else
|
270
|
+
self.class.unscoped.insert attributes_values
|
271
|
+
end
|
272
|
+
|
273
|
+
self.id ||= new_id
|
274
|
+
|
275
|
+
@new_record = false
|
276
|
+
id
|
277
|
+
end
|
278
|
+
|
279
|
+
# Initializes the attributes array with keys matching the columns from the linked table and
|
280
|
+
# the values matching the corresponding default value of that column, so
|
281
|
+
# that a new instance, or one populated from a passed-in Hash, still has all the attributes
|
282
|
+
# that instances loaded from the database would.
|
283
|
+
def attributes_from_column_definition
|
284
|
+
self.class.columns.inject({}) do |attributes, column|
|
285
|
+
attributes[column.name] = column.default unless column.name == self.class.primary_key
|
286
|
+
attributes
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'active_support/core_ext/object/blank'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
# = Active Record Query Cache
|
5
|
+
class QueryCache
|
6
|
+
module ClassMethods
|
7
|
+
# Enable the query cache within the block if Active Record is configured.
|
8
|
+
def cache(&block)
|
9
|
+
if ActiveRecord::Base.configurations.blank?
|
10
|
+
yield
|
11
|
+
else
|
12
|
+
connection.cache(&block)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Disable the query cache within the block if Active Record is configured.
|
17
|
+
def uncached(&block)
|
18
|
+
if ActiveRecord::Base.configurations.blank?
|
19
|
+
yield
|
20
|
+
else
|
21
|
+
connection.uncached(&block)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(app)
|
27
|
+
@app = app
|
28
|
+
end
|
29
|
+
|
30
|
+
def call(env)
|
31
|
+
ActiveRecord::Base.cache do
|
32
|
+
@app.call(env)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|