Module: ActiveRecord::Persistence::ClassMethods

Defined in:
lib/active_record/persistence.rb

Instance Method Summary collapse

Instance Method Details

#_delete_record(constraints) ⇒ Object

:nodoc:



284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/active_record/persistence.rb', line 284

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

#_insert_record(connection, values, returning) ⇒ Object

:nodoc:



238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/active_record/persistence.rb', line 238

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)

  with_connection do |c|
    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
end

#_update_record(values, constraints) ⇒ Object

:nodoc:



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
# File 'lib/active_record/persistence.rb', line 265

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

#build(attributes = nil, &block) ⇒ Object

Builds an object (or multiple objects) and returns either the built object or a list of built objects.

The attributes parameter can be either a Hash or an Array of Hashes. These Hashes describe the attributes on the objects that are to be built.

Examples

# Build a single new object
User.build(first_name: 'Jamie')

# Build an Array of new objects
User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])

# Build a single object and pass it into a block to set other attributes.
User.build(first_name: 'Jamie') do |u|
  u.is_admin = false
end

# Building an Array of new objects using a block, where the block is executed for each object:
User.build([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
  u.is_admin = false
end


82
83
84
85
86
87
88
# File 'lib/active_record/persistence.rb', line 82

def build(attributes = nil, &block)
  if attributes.is_a?(Array)
    attributes.collect { |attr| build(attr, &block) }
  else
    new(attributes, &block)
  end
end

#composite_query_constraints_listObject

Returns an array of column names to be used in queries. The source of column names is derived from query_constraints_list or primary_key. This method is for internal use when the primary key is to be treated as an array.



234
235
236
# File 'lib/active_record/persistence.rb', line 234

def composite_query_constraints_list # :nodoc:
  @composite_query_constraints_list ||= query_constraints_list || Array(primary_key)
end

#create(attributes = nil, &block) ⇒ Object

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.

The attributes parameter can be either a Hash or an Array of Hashes. These Hashes describe the attributes on the objects that are to be created.

Examples

# Create a single new object
User.create(first_name: 'Jamie')

# Create an Array of new objects
User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }])

# Create a single object and pass it into a block to set other attributes.
User.create(first_name: 'Jamie') do |u|
  u.is_admin = false
end

# Creating an Array of new objects using a block, where the block is executed for each object:
User.create([{ first_name: 'Jamie' }, { first_name: 'Jeremy' }]) do |u|
  u.is_admin = false
end


33
34
35
36
37
38
39
40
41
# File 'lib/active_record/persistence.rb', line 33

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

#create!(attributes = nil, &block) ⇒ Object

Creates an object (or multiple objects) and saves it to the database, if validations pass. Raises a RecordInvalid error if validations fail, unlike Base#create.

The attributes parameter can be either a Hash or an Array of Hashes. These describe which attributes to be created on the object, or multiple objects when given an Array of Hashes.



50
51
52
53
54
55
56
57
58
# File 'lib/active_record/persistence.rb', line 50

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

#has_query_constraints?Boolean

:nodoc:

Returns:

  • (Boolean)


219
220
221
# File 'lib/active_record/persistence.rb', line 219

def has_query_constraints? # :nodoc:
  @has_query_constraints
end

#instantiate(attributes, column_types = {}, &block) ⇒ Object

Given an attributes hash, instantiate returns a new instance of the appropriate class. Accepts only keys as strings.

For example, Post.all may return Comments, Messages, and Emails by storing the record’s subclass in a type attribute. By calling instantiate instead of new, finder methods ensure they get new instances of the appropriate class for each record.

See ActiveRecord::Inheritance#discriminate_class_for_record to see how this “single-table” inheritance mapping is implemented.



100
101
102
103
# File 'lib/active_record/persistence.rb', line 100

def instantiate(attributes, column_types = {}, &block)
  klass = discriminate_class_for_record(attributes)
  instantiate_instance_of(klass, attributes, column_types, &block)
end

#query_constraints(*columns_list) ⇒ Object

Accepts a list of attribute names to be used in the WHERE clause of SELECT / UPDATE / DELETE queries and in the ORDER BY clause for #first and #last finder methods.

class Developer < ActiveRecord::Base
  query_constraints :company_id, :id
end

developer = Developer.first
# SELECT "developers".* FROM "developers" ORDER BY "developers"."company_id" ASC, "developers"."id" ASC LIMIT 1
developer.inspect # => #<Developer id: 1, company_id: 1, ...>

developer.update!(name: "Nikita")
# UPDATE "developers" SET "name" = 'Nikita' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1

# It is possible to update an attribute used in the query_constraints clause:
developer.update!(company_id: 2)
# UPDATE "developers" SET "company_id" = 2 WHERE "developers"."company_id" = 1 AND "developers"."id" = 1

developer.name = "Bob"
developer.save!
# UPDATE "developers" SET "name" = 'Bob' WHERE "developers"."company_id" = 1 AND "developers"."id" = 1

developer.destroy!
# 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.reload
# SELECT "developers".* FROM "developers" WHERE "developers"."company_id" = 1 AND "developers"."id" = 1 LIMIT 1

Raises:

  • (ArgumentError)


212
213
214
215
216
217
# File 'lib/active_record/persistence.rb', line 212

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

#query_constraints_listObject

:nodoc:



223
224
225
226
227
228
229
# File 'lib/active_record/persistence.rb', line 223

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

#update(id = :all, attributes) ⇒ Object

Updates 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.

Parameters

  • id - This should be the id or an array of ids to be updated. Optional argument, defaults to all records in the relation.

  • attributes - This should be a hash of attributes or an array of hashes.

Examples

# Updates one record
Person.update(15, user_name: "Samuel", group: "expert")

# Updates multiple records
people = { 1 => { "first_name" => "David" }, 2 => { "first_name" => "Jeremy" } }
Person.update(people.keys, people.values)

# Updates multiple records from the result of a relation
people = Person.where(group: "expert")
people.update(group: "masters")

Note: Updating a large number of records will run an UPDATE query for each record, which may cause a performance issue. When running callbacks is not needed for each record update, it is preferred to use update_all for updating all records in a single query.



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/active_record/persistence.rb', line 132

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

#update!(id = :all, attributes) ⇒ Object

Updates the object (or multiple objects) just like #update but calls #update! instead of update, so an exception is raised if the record is invalid and saving will fail.



158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/active_record/persistence.rb', line 158

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