module ActiveRecord::Persistence::ClassMethods
def _delete_record(constraints) # :nodoc:
def _delete_record(constraints) # :nodoc: constraints = constraints.map { |name, value| predicate_builder[name, value] } default_constraint = build_default_constraint constraints << default_constraint if default_constraint if current_scope = self.global_current_scope constraints << current_scope.where_clause.ast end dm = Arel::DeleteManager.new(arel_table) dm.wheres = constraints with_connection do |c| c.delete(dm, "#{self} Destroy") end end
def _insert_record(connection, values, returning) # :nodoc:
def _insert_record(connection, values, returning) # :nodoc: primary_key = self.primary_key primary_key_value = nil if prefetch_primary_key? && primary_key values[primary_key] ||= begin primary_key_value = next_sequence_value _default_attributes[primary_key].with_cast_value(primary_key_value) end end im = Arel::InsertManager.new(arel_table) if values.empty? im.insert(connection.empty_insert_statement_value(primary_key)) else im.insert(values.transform_keys { |name| arel_table[name] }) end connection.insert( im, "#{self} Create", primary_key || false, primary_key_value, returning: returning ) end
def _update_record(values, constraints) # :nodoc:
def _update_record(values, constraints) # :nodoc: constraints = constraints.map { |name, value| predicate_builder[name, value] } default_constraint = build_default_constraint constraints << default_constraint if default_constraint if current_scope = self.global_current_scope constraints << current_scope.where_clause.ast end um = Arel::UpdateManager.new(arel_table) um.set(values.transform_keys { |name| arel_table[name] }) um.wheres = constraints with_connection do |c| c.update(um, "#{self} Update") end end
def build(attributes = nil, &block)
u.is_admin = false
User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
# Building an Array of new objects using a block, where the block is executed for each object:
end
u.is_admin = false
User.build(first_name: 'Jamie') do |u|
# Build a single object and pass it into a block to set other attributes.
User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
# Build an Array of new objects
User.build(first_name: 'Jamie')
# Build a single new object
==== Examples
attributes on the objects that are to be built.
The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
objects.
Builds an object (or multiple objects) and returns either the built object or a list of built
def build(attributes = nil, &block) if attributes.is_a?(Array) attributes.collect { |attr| build(attr, &block) } else new(attributes, &block) end end
def build_default_constraint
to build `where` clause from default scopes.
Called by +_update_record+ and +_delete_record+
def build_default_constraint return unless default_scopes?(all_queries: true) default_where_clause = default_scoped(all_queries: true).where_clause default_where_clause.ast unless default_where_clause.empty? end
def composite_query_constraints_list # :nodoc:
is for internal use when the primary key is to be treated as an array.
names is derived from +query_constraints_list+ or +primary_key+. This method
Returns an array of column names to be used in queries. The source of column
def composite_query_constraints_list # :nodoc: @composite_query_constraints_list ||= query_constraints_list || Array(primary_key) end
def create(attributes = nil, &block)
u.is_admin = false
User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
# Creating an Array of new objects using a block, where the block is executed for each object:
end
u.is_admin = false
User.create(first_name: 'Jamie') do |u|
# Create a single object and pass it into a block to set other attributes.
User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])
# Create an Array of new objects
User.create(first_name: 'Jamie')
# Create a single new object
==== Examples
attributes on the objects that are to be created.
The +attributes+ parameter can be either a Hash or an Array of Hashes. These Hashes describe the
The resulting object is returned whether the object was saved successfully to the database or not.
Creates an object (or multiple objects) and saves it to the database, if validations pass.
def create(attributes = nil, &block) if attributes.is_a?(Array) attributes.collect { |attr| create(attr, &block) } else object = new(attributes, &block) object.save object end end
def create!(attributes = nil, &block)
These describe which attributes to be created on the object, or
The +attributes+ parameter can be either a Hash or an Array of Hashes.
unlike Base#create.
if validations pass. Raises a RecordInvalid error if validations fail,
Creates an object (or multiple objects) and saves it to the database,
def create!(attributes = nil, &block) if attributes.is_a?(Array) attributes.collect { |attr| create!(attr, &block) } else object = new(attributes, &block) object.save! object end end
def discriminate_class_for_record(record)
See +ActiveRecord::Inheritance#discriminate_class_for_record+ for
record instance.
Called by +instantiate+ to decide which class to use for a new
def discriminate_class_for_record(record) self end
def has_query_constraints? # :nodoc:
def has_query_constraints? # :nodoc: @has_query_constraints end
def inherited(subclass)
def inherited(subclass) super subclass.class_eval do @_query_constraints_list = nil @has_query_constraints = false end end
def instantiate(attributes, column_types = {}, &block)
See ActiveRecord::Inheritance#discriminate_class_for_record to see
instances of the appropriate class for each record.
+instantiate+ instead of +new+, finder methods ensure they get new
by storing the record's subclass in a +type+ attribute. By calling
For example, +Post.all+ may return Comments, Messages, and Emails
the appropriate class. Accepts only keys as strings.
Given an attributes hash, +instantiate+ returns a new instance of
def instantiate(attributes, column_types = {}, &block) klass = discriminate_class_for_record(attributes) instantiate_instance_of(klass, attributes, column_types, &block) end
def instantiate_instance_of(klass, attributes, column_types = {}, &block)
Given a class, an attributes hash, +instantiate_instance_of+ returns a
def instantiate_instance_of(klass, attributes, column_types = {}, &block) attributes = klass.attributes_builder.build_from_database(attributes, column_types) klass.allocate.init_with_attributes(attributes, &block) end
def query_constraints(*columns_list)
developer.reload
# DELETE FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
developer.delete
# DELETE FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
developer.destroy!
# UPDATE "developers" SET "name" = 'Bob' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
developer.save!
developer.name = "Bob"
# UPDATE "developers" SET "company_id" = 2 WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
developer.update!(company_id: 2)
# It is possible to update an attribute used in the query_constraints clause:
# UPDATE "developers" SET "name" = 'Nikita' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1
developer.update!(name: "Nikita")
developer.inspect # => #
# SELECT "developers".* FROM "developers" ORDER BY "developers"."company_id" ASC, "developers"."id" ASC LIMIT 1
developer = Developer.first
end
query_constraints :company_id, :id
class Developer < ActiveRecord::Base
of SELECT / UPDATE / DELETE queries and in the ORDER BY clause for +#first+ and +#last+ finder methods.
Accepts a list of attribute names to be used in the WHERE clause
def query_constraints(*columns_list) raise ArgumentError, "You must specify at least one column to be used in querying" if columns_list.empty? @query_constraints_list = columns_list.map(&:to_s) @has_query_constraints = @query_constraints_list end
def query_constraints_list # :nodoc:
def query_constraints_list # :nodoc: @query_constraints_list ||= if base_class? || primary_key != base_class.primary_key primary_key if primary_key.is_a?(Array) else base_class.query_constraints_list end end
def update(id = :all, attributes)
it is preferred to use {update_all}[rdoc-ref:Relation#update_all]
When running callbacks is not needed for each record update,
query for each record, which may cause a performance issue.
Note: Updating a large number of records will run an UPDATE
people.update(group: "masters")
people = Person.where(group: "expert")
# Updates multiple records from the result of a relation
Person.update(people.keys, people.values)
people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
# Updates multiple records
Person.update(15, user_name: "Samuel", group: "expert")
# Updates one record
==== Examples
* +attributes+ - This should be a hash of attributes or an array of hashes.
Optional argument, defaults to all records in the relation.
* +id+ - This should be the id or an array of ids to be updated.
==== Parameters
The resulting object is returned whether the object was saved successfully to the database or not.
Updates an object (or multiple objects) and saves it to the database, if validations pass.
def update(id = :all, attributes) if id.is_a?(Array) if id.any?(ActiveRecord::Base) raise ArgumentError, "You are passing an array of ActiveRecord::Base instances to `update`. " \ "Please pass the ids of the objects by calling `pluck(:id)` or `map(&:id)`." end id.map { |one_id| find(one_id) }.each_with_index { |object, idx| object.update(attributes[idx]) } elsif id == :all all.each { |record| record.update(attributes) } else if ActiveRecord::Base === id raise ArgumentError, "You are passing an instance of ActiveRecord::Base to `update`. " \ "Please pass the id of the object by calling `.id`." end object = find(id) object.update(attributes) object end end
def update!(id = :all, attributes)
Updates the object (or multiple objects) just like #update but calls #update! instead
def update!(id = :all, attributes) if id.is_a?(Array) if id.any?(ActiveRecord::Base) raise ArgumentError, "You are passing an array of ActiveRecord::Base instances to `update!`. " \ "Please pass the ids of the objects by calling `pluck(:id)` or `map(&:id)`." end id.map { |one_id| find(one_id) }.each_with_index { |object, idx| object.update!(attributes[idx]) } elsif id == :all all.each { |record| record.update!(attributes) } else if ActiveRecord::Base === id raise ArgumentError, "You are passing an instance of ActiveRecord::Base to `update!`. " \ "Please pass the id of the object by calling `.id`." end object = find(id) object.update!(attributes) object end end