2010-05-08 19:06:05 -04:00
|
|
|
module ActiveRecord
|
2010-06-16 13:38:14 -04:00
|
|
|
# = Active Record Persistence
|
2010-05-08 19:06:05 -04:00
|
|
|
module Persistence
|
2011-12-15 15:07:41 -05:00
|
|
|
extend ActiveSupport::Concern
|
|
|
|
|
|
|
|
module ClassMethods
|
|
|
|
# Creates an object (or multiple objects) and saves it to the database, if validations pass.
|
|
|
|
# The resulting object is returned whether the object was saved successfully to the database or not.
|
|
|
|
#
|
2011-12-25 08:28:25 -05:00
|
|
|
# The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
|
2011-12-15 15:07:41 -05:00
|
|
|
# attributes on the objects that are to be created.
|
|
|
|
#
|
|
|
|
# +create+ respects mass-assignment security and accepts either +:as+ or +:without_protection+ options
|
|
|
|
# in the +options+ parameter.
|
|
|
|
#
|
|
|
|
# ==== Examples
|
|
|
|
# # Create a single new object
|
2012-10-23 07:02:34 -04:00
|
|
|
# User.create(first_name: 'Jamie')
|
2011-12-15 15:07:41 -05:00
|
|
|
#
|
|
|
|
# # Create an Array of new objects
|
2012-10-23 07:02:34 -04:00
|
|
|
# User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
|
2011-12-15 15:07:41 -05:00
|
|
|
#
|
|
|
|
# # Create a single object and pass it into a block to set other attributes.
|
2012-10-23 07:02:34 -04:00
|
|
|
# User.create(first_name: 'Jamie') do |u|
|
2011-12-15 15:07:41 -05:00
|
|
|
# u.is_admin = false
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# # Creating an Array of new objects using a block, where the block is executed for each object:
|
2012-10-23 07:02:34 -04:00
|
|
|
# User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
|
2011-12-15 15:07:41 -05:00
|
|
|
# u.is_admin = false
|
|
|
|
# end
|
2012-09-12 12:35:05 -04:00
|
|
|
def create(attributes = nil, &block)
|
2011-12-15 15:07:41 -05:00
|
|
|
if attributes.is_a?(Array)
|
2012-09-12 12:35:05 -04:00
|
|
|
attributes.collect { |attr| create(attr, &block) }
|
2011-12-15 15:07:41 -05:00
|
|
|
else
|
2012-09-12 12:35:05 -04:00
|
|
|
object = new(attributes, &block)
|
2011-12-15 15:07:41 -05:00
|
|
|
object.save
|
|
|
|
object
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2010-08-12 11:04:16 -04:00
|
|
|
# Returns true if this object hasn't been saved yet -- that is, a record
|
2010-06-16 13:38:14 -04:00
|
|
|
# for the object doesn't exist in the data store yet; otherwise, returns false.
|
2010-05-08 19:06:05 -04:00
|
|
|
def new_record?
|
2010-11-28 10:55:48 -05:00
|
|
|
@new_record
|
2010-05-08 19:06:05 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Returns true if this object has been destroyed, otherwise returns false.
|
|
|
|
def destroyed?
|
|
|
|
@destroyed
|
|
|
|
end
|
|
|
|
|
2011-12-25 08:41:50 -05:00
|
|
|
# Returns true if the record is persisted, i.e. it's not a new record and it was
|
|
|
|
# not destroyed, otherwise returns false.
|
2010-05-08 19:06:05 -04:00
|
|
|
def persisted?
|
2010-11-28 10:55:48 -05:00
|
|
|
!(new_record? || destroyed?)
|
2010-05-08 19:06:05 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Saves the model.
|
|
|
|
#
|
|
|
|
# If the model is new a record gets created in the database, otherwise
|
|
|
|
# the existing record gets updated.
|
|
|
|
#
|
|
|
|
# By default, save always run validations. If any of them fail the action
|
|
|
|
# is cancelled and +save+ returns +false+. However, if you supply
|
2012-10-23 07:02:34 -04:00
|
|
|
# validate: false, validations are bypassed altogether. See
|
2010-05-08 19:06:05 -04:00
|
|
|
# ActiveRecord::Validations for more information.
|
|
|
|
#
|
|
|
|
# There's a series of callbacks associated with +save+. If any of the
|
|
|
|
# <tt>before_*</tt> callbacks return +false+ the action is cancelled and
|
|
|
|
# +save+ returns +false+. See ActiveRecord::Callbacks for further
|
|
|
|
# details.
|
|
|
|
def save(*)
|
2012-11-19 09:50:44 -05:00
|
|
|
create_or_update
|
|
|
|
rescue ActiveRecord::RecordInvalid
|
|
|
|
false
|
2010-05-08 19:06:05 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Saves the model.
|
|
|
|
#
|
|
|
|
# If the model is new a record gets created in the database, otherwise
|
|
|
|
# the existing record gets updated.
|
|
|
|
#
|
|
|
|
# With <tt>save!</tt> validations always run. If any of them fail
|
|
|
|
# ActiveRecord::RecordInvalid gets raised. See ActiveRecord::Validations
|
|
|
|
# for more information.
|
|
|
|
#
|
|
|
|
# There's a series of callbacks associated with <tt>save!</tt>. If any of
|
|
|
|
# the <tt>before_*</tt> callbacks return +false+ the action is cancelled
|
|
|
|
# and <tt>save!</tt> raises ActiveRecord::RecordNotSaved. See
|
|
|
|
# ActiveRecord::Callbacks for further details.
|
|
|
|
def save!(*)
|
|
|
|
create_or_update || raise(RecordNotSaved)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Deletes the record in the database and freezes this instance to
|
|
|
|
# reflect that no changes should be made (since they can't be
|
|
|
|
# persisted). Returns the frozen instance.
|
|
|
|
#
|
2010-08-04 19:09:09 -04:00
|
|
|
# The row is simply removed with an SQL +DELETE+ statement on the
|
2010-05-08 19:06:05 -04:00
|
|
|
# record's primary key, and no callbacks are executed.
|
|
|
|
#
|
|
|
|
# To enforce the object's +before_destroy+ and +after_destroy+
|
2012-10-14 19:00:57 -04:00
|
|
|
# callbacks or any <tt>:dependent</tt> association
|
2010-05-08 19:06:05 -04:00
|
|
|
# options, use <tt>#destroy</tt>.
|
|
|
|
def delete
|
2012-03-01 22:10:06 -05:00
|
|
|
self.class.delete(id) if persisted?
|
2010-05-08 19:06:05 -04:00
|
|
|
@destroyed = true
|
|
|
|
freeze
|
|
|
|
end
|
|
|
|
|
2010-08-12 11:04:16 -04:00
|
|
|
# Deletes the record in the database and freezes this instance to reflect
|
2010-06-16 13:38:14 -04:00
|
|
|
# that no changes should be made (since they can't be persisted).
|
2012-06-05 02:35:05 -04:00
|
|
|
#
|
|
|
|
# There's a series of callbacks associated with <tt>destroy</tt>. If
|
|
|
|
# the <tt>before_destroy</tt> callback return +false+ the action is cancelled
|
|
|
|
# and <tt>destroy</tt> returns +false+. See
|
|
|
|
# ActiveRecord::Callbacks for further details.
|
2010-05-08 19:06:05 -04:00
|
|
|
def destroy
|
2012-05-10 07:47:50 -04:00
|
|
|
raise ReadOnlyRecord if readonly?
|
2011-05-31 10:43:19 -04:00
|
|
|
destroy_associations
|
2012-03-30 09:39:55 -04:00
|
|
|
destroy_row if persisted?
|
2010-05-08 19:06:05 -04:00
|
|
|
@destroyed = true
|
|
|
|
freeze
|
|
|
|
end
|
|
|
|
|
2012-06-05 02:35:05 -04:00
|
|
|
# Deletes the record in the database and freezes this instance to reflect
|
|
|
|
# that no changes should be made (since they can't be persisted).
|
|
|
|
#
|
|
|
|
# There's a series of callbacks associated with <tt>destroy!</tt>. If
|
|
|
|
# the <tt>before_destroy</tt> callback return +false+ the action is cancelled
|
|
|
|
# and <tt>destroy!</tt> raises ActiveRecord::RecordNotDestroyed. See
|
|
|
|
# ActiveRecord::Callbacks for further details.
|
|
|
|
def destroy!
|
|
|
|
destroy || raise(ActiveRecord::RecordNotDestroyed)
|
|
|
|
end
|
|
|
|
|
2010-08-12 11:04:16 -04:00
|
|
|
# Returns an instance of the specified +klass+ with the attributes of the
|
|
|
|
# current record. This is mostly useful in relation to single-table
|
|
|
|
# inheritance structures where you want a subclass to appear as the
|
|
|
|
# superclass. This can be used along with record identification in
|
|
|
|
# Action Pack to allow, say, <tt>Client < Company</tt> to do something
|
2012-10-23 07:02:34 -04:00
|
|
|
# like render <tt>partial: @client.becomes(Company)</tt> to render that
|
2010-06-16 13:38:14 -04:00
|
|
|
# instance using the companies/company partial instead of clients/client.
|
2010-05-08 19:06:05 -04:00
|
|
|
#
|
2010-08-12 11:04:16 -04:00
|
|
|
# Note: The new instance will share a link to the same attributes as the original class.
|
2010-08-02 12:25:26 -04:00
|
|
|
# So any change to the attributes in either instance will affect the other.
|
2010-05-08 19:06:05 -04:00
|
|
|
def becomes(klass)
|
|
|
|
became = klass.new
|
|
|
|
became.instance_variable_set("@attributes", @attributes)
|
|
|
|
became.instance_variable_set("@attributes_cache", @attributes_cache)
|
2010-11-28 10:55:48 -05:00
|
|
|
became.instance_variable_set("@new_record", new_record?)
|
2010-05-08 19:06:05 -04:00
|
|
|
became.instance_variable_set("@destroyed", destroyed?)
|
2011-10-26 07:51:38 -04:00
|
|
|
became.instance_variable_set("@errors", errors)
|
2011-09-14 11:32:31 -04:00
|
|
|
became
|
|
|
|
end
|
|
|
|
|
|
|
|
# Wrapper around +becomes+ that also changes the instance's sti column value.
|
|
|
|
# This is especially useful if you want to persist the changed class in your
|
|
|
|
# database.
|
|
|
|
#
|
|
|
|
# Note: The old instance's sti column value will be changed too, as both objects
|
|
|
|
# share the same set of attributes.
|
|
|
|
def becomes!(klass)
|
|
|
|
became = becomes(klass)
|
|
|
|
became.public_send("#{klass.inheritance_column}=", klass.sti_name) unless self.class.descends_from_active_record?
|
2010-05-08 19:06:05 -04:00
|
|
|
became
|
|
|
|
end
|
|
|
|
|
2012-08-25 21:54:55 -04:00
|
|
|
# Updates a single attribute and saves the record.
|
|
|
|
# This is especially useful for boolean flags on existing records. Also note that
|
|
|
|
#
|
|
|
|
# * Validation is skipped.
|
|
|
|
# * Callbacks are invoked.
|
|
|
|
# * updated_at/updated_on column is updated if that column is available.
|
|
|
|
# * Updates all the attributes that are dirty in this object.
|
|
|
|
#
|
|
|
|
def update_attribute(name, value)
|
|
|
|
name = name.to_s
|
|
|
|
verify_readonly_attribute(name)
|
|
|
|
send("#{name}=", value)
|
2012-11-20 19:44:33 -05:00
|
|
|
save(validate: false)
|
2012-08-25 21:54:55 -04:00
|
|
|
end
|
|
|
|
|
2010-07-14 11:42:48 -04:00
|
|
|
# Updates the attributes of the model from the passed-in hash and saves the
|
|
|
|
# record, all wrapped in a transaction. If the object is invalid, the saving
|
|
|
|
# will fail and false will be returned.
|
2012-09-12 12:35:05 -04:00
|
|
|
def update_attributes(attributes)
|
2010-07-14 11:42:48 -04:00
|
|
|
# The following transaction covers any possible database side-effects of the
|
|
|
|
# attributes assignment. For example, setting the IDs of a child collection.
|
2010-07-13 15:30:23 -04:00
|
|
|
with_transaction_returning_status do
|
2012-09-12 12:35:05 -04:00
|
|
|
assign_attributes(attributes)
|
2010-07-13 15:30:23 -04:00
|
|
|
save
|
|
|
|
end
|
2010-05-08 19:06:05 -04:00
|
|
|
end
|
|
|
|
|
2010-07-14 11:42:48 -04:00
|
|
|
# Updates its receiver just like +update_attributes+ but calls <tt>save!</tt> instead
|
|
|
|
# of +save+, so an exception is raised if the record is invalid.
|
2012-09-12 12:35:05 -04:00
|
|
|
def update_attributes!(attributes)
|
2010-07-14 11:42:48 -04:00
|
|
|
# The following transaction covers any possible database side-effects of the
|
|
|
|
# attributes assignment. For example, setting the IDs of a child collection.
|
2010-07-13 15:30:23 -04:00
|
|
|
with_transaction_returning_status do
|
2012-09-12 12:35:05 -04:00
|
|
|
assign_attributes(attributes)
|
2010-07-13 15:30:23 -04:00
|
|
|
save!
|
|
|
|
end
|
2010-05-08 19:06:05 -04:00
|
|
|
end
|
|
|
|
|
2012-10-10 15:29:52 -04:00
|
|
|
# Updates a single attribute of an object, without having to explicitly call save on that object.
|
2012-07-24 18:13:18 -04:00
|
|
|
#
|
|
|
|
# * Validation is skipped.
|
|
|
|
# * Callbacks are skipped.
|
|
|
|
# * updated_at/updated_on column is not updated if that column is available.
|
|
|
|
#
|
|
|
|
# Raises an +ActiveRecordError+ when called on new objects, or when the +name+
|
|
|
|
# attribute is marked as readonly.
|
|
|
|
def update_column(name, value)
|
|
|
|
update_columns(name => value)
|
|
|
|
end
|
|
|
|
|
2012-10-10 15:29:52 -04:00
|
|
|
# Updates the attributes from the passed-in hash, without having to explicitly call save on that object.
|
2011-05-21 12:14:55 -04:00
|
|
|
#
|
|
|
|
# * Validation is skipped.
|
|
|
|
# * Callbacks are skipped.
|
|
|
|
# * updated_at/updated_on column is not updated if that column is available.
|
|
|
|
#
|
|
|
|
# Raises an +ActiveRecordError+ when called on new objects, or when at least
|
|
|
|
# one of the attributes is marked as readonly.
|
|
|
|
def update_columns(attributes)
|
|
|
|
raise ActiveRecordError, "can not update on a new record object" unless persisted?
|
2012-07-24 18:13:18 -04:00
|
|
|
|
|
|
|
attributes.each_key do |key|
|
2012-08-25 21:59:40 -04:00
|
|
|
verify_readonly_attribute(key.to_s)
|
2012-07-24 18:13:18 -04:00
|
|
|
end
|
|
|
|
|
2012-10-28 12:48:04 -04:00
|
|
|
updated_count = self.class.where(self.class.primary_key => id).update_all(attributes)
|
|
|
|
|
2012-11-20 19:44:33 -05:00
|
|
|
attributes.each do |k, v|
|
|
|
|
raw_write_attribute(k, v)
|
2011-05-21 12:14:55 -04:00
|
|
|
end
|
2012-07-24 18:13:18 -04:00
|
|
|
|
2012-10-28 12:48:04 -04:00
|
|
|
updated_count == 1
|
2011-05-21 12:14:55 -04:00
|
|
|
end
|
|
|
|
|
2010-05-08 19:06:05 -04:00
|
|
|
# Initializes +attribute+ to zero if +nil+ and adds the value passed as +by+ (default is 1).
|
|
|
|
# The increment is performed directly on the underlying attribute, no setter is invoked.
|
|
|
|
# Only makes sense for number-based attributes. Returns +self+.
|
|
|
|
def increment(attribute, by = 1)
|
|
|
|
self[attribute] ||= 0
|
|
|
|
self[attribute] += by
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
# Wrapper around +increment+ that saves the record. This method differs from
|
|
|
|
# its non-bang version in that it passes through the attribute setter.
|
|
|
|
# Saving is not subjected to validation checks. Returns +true+ if the
|
|
|
|
# record could be saved.
|
|
|
|
def increment!(attribute, by = 1)
|
2012-08-25 21:54:55 -04:00
|
|
|
increment(attribute, by).update_attribute(attribute, self[attribute])
|
2010-05-08 19:06:05 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Initializes +attribute+ to zero if +nil+ and subtracts the value passed as +by+ (default is 1).
|
|
|
|
# The decrement is performed directly on the underlying attribute, no setter is invoked.
|
|
|
|
# Only makes sense for number-based attributes. Returns +self+.
|
|
|
|
def decrement(attribute, by = 1)
|
|
|
|
self[attribute] ||= 0
|
|
|
|
self[attribute] -= by
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
# Wrapper around +decrement+ that saves the record. This method differs from
|
|
|
|
# its non-bang version in that it passes through the attribute setter.
|
|
|
|
# Saving is not subjected to validation checks. Returns +true+ if the
|
|
|
|
# record could be saved.
|
|
|
|
def decrement!(attribute, by = 1)
|
2012-08-25 21:54:55 -04:00
|
|
|
decrement(attribute, by).update_attribute(attribute, self[attribute])
|
2010-05-08 19:06:05 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Assigns to +attribute+ the boolean opposite of <tt>attribute?</tt>. So
|
|
|
|
# if the predicate returns +true+ the attribute will become +false+. This
|
|
|
|
# method toggles directly the underlying value without calling any setter.
|
|
|
|
# Returns +self+.
|
|
|
|
def toggle(attribute)
|
|
|
|
self[attribute] = !send("#{attribute}?")
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
|
|
|
# Wrapper around +toggle+ that saves the record. This method differs from
|
|
|
|
# its non-bang version in that it passes through the attribute setter.
|
|
|
|
# Saving is not subjected to validation checks. Returns +true+ if the
|
|
|
|
# record could be saved.
|
|
|
|
def toggle!(attribute)
|
2012-08-25 21:54:55 -04:00
|
|
|
toggle(attribute).update_attribute(attribute, self[attribute])
|
2010-05-08 19:06:05 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Reloads the attributes of this object from the database.
|
|
|
|
# The optional options argument is passed to find when reloading so you
|
2012-10-23 07:02:34 -04:00
|
|
|
# may do e.g. record.reload(lock: true) to reload the same record with
|
2010-05-08 19:06:05 -04:00
|
|
|
# an exclusive row lock.
|
|
|
|
def reload(options = nil)
|
2012-07-27 17:21:29 -04:00
|
|
|
clear_aggregation_cache
|
2010-05-08 19:06:05 -04:00
|
|
|
clear_association_cache
|
2010-08-28 14:56:02 -04:00
|
|
|
|
2012-04-29 13:10:43 -04:00
|
|
|
fresh_object =
|
2012-04-29 13:33:54 -04:00
|
|
|
if options && options[:lock]
|
2012-04-29 13:10:43 -04:00
|
|
|
self.class.unscoped { self.class.lock.find(id) }
|
|
|
|
else
|
|
|
|
self.class.unscoped { self.class.find(id) }
|
|
|
|
end
|
|
|
|
|
2012-03-01 22:10:06 -05:00
|
|
|
@attributes.update(fresh_object.instance_variable_get('@attributes'))
|
|
|
|
@columns_hash = fresh_object.instance_variable_get('@columns_hash')
|
2010-08-28 14:56:02 -04:00
|
|
|
|
2010-05-08 19:06:05 -04:00
|
|
|
@attributes_cache = {}
|
|
|
|
self
|
|
|
|
end
|
|
|
|
|
2010-08-02 10:16:02 -04:00
|
|
|
# Saves the record with the updated_at/on attributes set to the current time.
|
|
|
|
# Please note that no validation is performed and no callbacks are executed.
|
2010-08-12 11:04:16 -04:00
|
|
|
# If an attribute name is passed, that attribute is updated along with
|
2010-08-02 10:16:02 -04:00
|
|
|
# updated_at/on attributes.
|
|
|
|
#
|
|
|
|
# product.touch # updates updated_at/on
|
|
|
|
# product.touch(:designed_at) # updates the designed_at attribute and updated_at/on
|
2010-08-24 10:21:58 -04:00
|
|
|
#
|
|
|
|
# If used along with +belongs_to+ then +touch+ will invoke +touch+ method on associated object.
|
|
|
|
#
|
2010-08-24 18:22:53 -04:00
|
|
|
# class Brake < ActiveRecord::Base
|
2012-10-23 07:02:34 -04:00
|
|
|
# belongs_to :car, touch: true
|
2010-08-24 18:22:53 -04:00
|
|
|
# end
|
|
|
|
#
|
|
|
|
# class Car < ActiveRecord::Base
|
2012-10-23 07:02:34 -04:00
|
|
|
# belongs_to :corporation, touch: true
|
2010-08-24 18:22:53 -04:00
|
|
|
# end
|
|
|
|
#
|
|
|
|
# # triggers @brake.car.touch and @brake.car.corporation.touch
|
|
|
|
# @brake.touch
|
2010-08-12 11:04:16 -04:00
|
|
|
def touch(name = nil)
|
|
|
|
attributes = timestamp_attributes_for_update_in_model
|
2010-09-24 13:35:35 -04:00
|
|
|
attributes << name if name
|
2010-11-27 05:14:26 -05:00
|
|
|
|
2010-09-24 13:35:35 -04:00
|
|
|
unless attributes.empty?
|
2010-08-24 09:56:26 -04:00
|
|
|
current_time = current_time_from_proper_timezone
|
|
|
|
changes = {}
|
2010-08-12 11:04:16 -04:00
|
|
|
|
2010-08-24 09:56:26 -04:00
|
|
|
attributes.each do |column|
|
2012-03-03 00:10:39 -05:00
|
|
|
column = column.to_s
|
|
|
|
changes[column] = write_attribute(column, current_time)
|
2010-08-24 09:56:26 -04:00
|
|
|
end
|
2010-08-12 11:04:16 -04:00
|
|
|
|
2011-02-09 09:24:32 -05:00
|
|
|
changes[self.class.locking_column] = increment_lock if locking_enabled?
|
2010-11-27 05:14:26 -05:00
|
|
|
|
2010-08-24 09:56:26 -04:00
|
|
|
@changed_attributes.except!(*changes.keys)
|
|
|
|
primary_key = self.class.primary_key
|
2012-04-26 08:29:10 -04:00
|
|
|
self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
|
2010-08-24 09:56:26 -04:00
|
|
|
end
|
2010-08-02 10:16:02 -04:00
|
|
|
end
|
|
|
|
|
2010-05-08 19:06:05 -04:00
|
|
|
private
|
2011-05-31 10:43:19 -04:00
|
|
|
|
2011-07-24 17:04:52 -04:00
|
|
|
# A hook to be overridden by association modules.
|
2011-05-31 10:43:19 -04:00
|
|
|
def destroy_associations
|
|
|
|
end
|
|
|
|
|
2012-03-30 09:39:55 -04:00
|
|
|
def destroy_row
|
|
|
|
relation_for_destroy.delete_all
|
|
|
|
end
|
|
|
|
|
|
|
|
def relation_for_destroy
|
|
|
|
pk = self.class.primary_key
|
|
|
|
column = self.class.columns_hash[pk]
|
|
|
|
substitute = connection.substitute_at(column, 0)
|
|
|
|
|
|
|
|
relation = self.class.unscoped.where(
|
|
|
|
self.class.arel_table[pk].eq(substitute))
|
|
|
|
|
|
|
|
relation.bind_values = [[column, id]]
|
|
|
|
relation
|
|
|
|
end
|
|
|
|
|
2010-05-08 19:06:05 -04:00
|
|
|
def create_or_update
|
|
|
|
raise ReadOnlyRecord if readonly?
|
2010-11-28 10:55:48 -05:00
|
|
|
result = new_record? ? create : update
|
2010-05-08 19:06:05 -04:00
|
|
|
result != false
|
|
|
|
end
|
|
|
|
|
|
|
|
# Updates the associated record with values matching those of the instance attributes.
|
|
|
|
# Returns the number of affected rows.
|
|
|
|
def update(attribute_names = @attributes.keys)
|
2012-03-06 17:54:38 -05:00
|
|
|
attributes_with_values = arel_attributes_with_values_for_update(attribute_names)
|
2012-11-20 19:44:33 -05:00
|
|
|
|
|
|
|
if attributes_with_values.empty?
|
|
|
|
0
|
|
|
|
else
|
|
|
|
klass = self.class
|
|
|
|
stmt = klass.unscoped.where(klass.arel_table[klass.primary_key].eq(id)).arel.compile_update(attributes_with_values)
|
|
|
|
klass.connection.update stmt
|
|
|
|
end
|
2010-05-08 19:06:05 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Creates a record with values matching those of the instance attributes
|
|
|
|
# and returns its id.
|
2012-09-28 12:55:35 -04:00
|
|
|
def create(attribute_names = @attributes.keys)
|
|
|
|
attributes_values = arel_attributes_with_values_for_create(attribute_names)
|
2010-05-08 19:06:05 -04:00
|
|
|
|
2011-03-22 12:18:01 -04:00
|
|
|
new_id = self.class.unscoped.insert attributes_values
|
2011-10-05 13:11:25 -04:00
|
|
|
self.id ||= new_id if self.class.primary_key
|
2010-05-08 19:06:05 -04:00
|
|
|
|
2010-11-28 10:55:48 -05:00
|
|
|
@new_record = false
|
2010-05-08 19:06:05 -04:00
|
|
|
id
|
|
|
|
end
|
2012-08-25 21:55:03 -04:00
|
|
|
|
|
|
|
def verify_readonly_attribute(name)
|
|
|
|
raise ActiveRecordError, "#{name} is marked as readonly" if self.class.readonly_attributes.include?(name)
|
|
|
|
end
|
2010-05-08 19:06:05 -04:00
|
|
|
end
|
2010-06-30 07:14:09 -04:00
|
|
|
end
|