Spec-Zone.ru › Ruby on Rails 4.1

модуль ActiveRecord::Persistence

Active Record Персистентность

Методы открытого экземпляра

becomes(klass) Показать исходный код

Возвращает экземпляр указанного klass с атрибутами текущей записи. Это в основном полезно в отношении структур единой таблицы наследования, где вы хотите, чтобы подкласс отображался как суперкласс. Это можно использовать вместе с идентификацией записей в Action Pack, чтобы, скажем, Client < Company смог сделать что-то вроде render partial: @client.becomes(Company) для отображения этого экземпляра с помощью части companies/company вместо clients/client.

Примечание: новый экземпляр будет разделять ссылку на те же атрибуты, что и исходный класс. Поэтому любое изменение атрибутов в любом экземпляре повлияет на другой.

# File activerecord/lib/active_record/persistence.rb, line 180
def becomes(klass)
  became = klass.new
  became.instance_variable_set("@attributes", @attributes)
  became.instance_variable_set("@attributes_cache", @attributes_cache)
  changed_attributes = @changed_attributes if defined?(@changed_attributes)
  became.instance_variable_set("@changed_attributes", changed_attributes || {})
  became.instance_variable_set("@new_record", new_record?)
  became.instance_variable_set("@destroyed", destroyed?)
  became.instance_variable_set("@errors", errors)
  became
end
becomes!(klass) Показать исходный код

Обёртка вокруг becomes, которая также изменяет значение столбца sti экземпляра. Это особенно полезно, если вы хотите сохранить изменённый класс в вашей базе данных.

Примечание: значение столбца sti старого экземпляра также будет изменено, так как оба объекта разделяют один и тот же набор атрибутов.

# File activerecord/lib/active_record/persistence.rb, line 198
def becomes!(klass)
  became = becomes(klass)
  sti_type = nil
  if !klass.descends_from_active_record?
    sti_type = klass.sti_name
  end
  became.public_send("#{klass.inheritance_column}=", sti_type)
  became
end
decrement(attribute, by = 1) Показать исходный код

Инициализирует attribute значением ноль, если nil , и вычитает значение, переданное в качестве by (по умолчанию 1). Уменьшение выполняется непосредственно над базовым атрибутом, вызов сеттера не выполняется. Имеет смысл только для числовых атрибутов. Возвращает self.

# File activerecord/lib/active_record/persistence.rb, line 308
def decrement(attribute, by = 1)
  self[attribute] ||= 0
  self[attribute] -= by
  self
end
decrement!(attribute, by = 1) Показать исходный код

Обёртка вокруг decrement , которая сохраняет запись. Этот метод отличается от своего варианта без восклицательного знака тем, что он проходит через сеттер атрибута. Сохранение не подлежит проверке валидации. Возвращает true , если запись была сохранена.

# File activerecord/lib/active_record/persistence.rb, line 318
def decrement!(attribute, by = 1)
  decrement(attribute, by).update_attribute(attribute, self[attribute])
end
delete() Показать исходный код

Удаляет запись в базе данных и замораживает этот экземпляр, чтобы отразить, что никакие изменения не должны быть внесены (поскольку они не могут быть сохранены). Возвращает замороженный экземпляр.

Строка просто удаляется с помощью SQL DELETE -выражения по первичному ключу записи, и никакие обратные вызовы не выполняются.

Чтобы применить обратные вызовы before_destroy и after_destroy или любые параметры ассоциации :dependent, используйте #destroy.

# File activerecord/lib/active_record/persistence.rb, line 138
def delete
  self.class.delete(id) if persisted?
  @destroyed = true
  freeze
end
destroy() Показать исходный код

Удаляет запись в базе данных и замораживает этот экземпляр, чтобы отразить, что никакие изменения не должны быть внесены (поскольку они не могут быть сохранены).

Существует ряд обратных вызовов, связанных с destroy. Если обратный вызов before_destroy вернёт false, действие отменяется и destroy возвращает false. Дополнительные сведения см. в ActiveRecord::Callbacks.

# File activerecord/lib/active_record/persistence.rb, line 151
def destroy
  raise ReadOnlyRecord if readonly?
  destroy_associations
  destroy_row if persisted?
  @destroyed = true
  freeze
end
destroy!() Показать исходный код

Удаляет запись в базе данных и замораживает этот экземпляр, чтобы отразить, что никакие изменения не должны быть внесены (поскольку они не могут быть сохранены).

Существует ряд обратных вызовов, связанных с destroy!. Если обратный вызов before_destroy вернёт false, действие отменяется и destroy! поднимает ActiveRecord::RecordNotDestroyed. Дополнительные сведения см. в ActiveRecord::Callbacks.

# File activerecord/lib/active_record/persistence.rb, line 166
def destroy!
  destroy || raise(ActiveRecord::RecordNotDestroyed)
end
destroyed?() Показать исходный код

Возвращает true, если этот объект был уничтожен, в противном случае возвращает false.

# File activerecord/lib/active_record/persistence.rb, line 74
def destroyed?
  sync_with_transaction_state
  @destroyed
end
increment(attribute, by = 1) Показать исходный код

Инициализирует attribute значением ноль, если nil , и добавляет значение, переданное в качестве by (по умолчанию 1). Увеличение выполняется непосредственно над базовым атрибутом, вызов сеттера не выполняется. Имеет смысл только для числовых атрибутов. Возвращает self.

# File activerecord/lib/active_record/persistence.rb, line 291
def increment(attribute, by = 1)
  self[attribute] ||= 0
  self[attribute] += by
  self
end
increment!(attribute, by = 1) Показать исходный код

Обёртка вокруг increment , которая сохраняет запись. Этот метод отличается от своего варианта без восклицательного знака тем, что он проходит через сеттер атрибута. Сохранение не подлежит проверке валидации. Возвращает true , если запись была сохранена.

# File activerecord/lib/active_record/persistence.rb, line 301
def increment!(attribute, by = 1)
  increment(attribute, by).update_attribute(attribute, self[attribute])
end
new_record?() Показать исходный код

Возвращает true, если этот объект ещё не сохранён — то есть, запись для объекта ещё не существует в базе данных; в противном случае возвращает false.

# File activerecord/lib/active_record/persistence.rb, line 68
def new_record?
  sync_with_transaction_state
  @new_record
end
persisted?() Показать исходный код

Возвращает true, если запись сохранена, т. е. это не новая запись и она не была удалена, в противном случае возвращает false.

# File activerecord/lib/active_record/persistence.rb, line 81
def persisted?
  !(new_record? || destroyed?)
end
reload(options = nil) Показать исходный код

Перезагружает запись из базы данных.

Этот метод находит запись по её первичному ключу (который можно задать вручную) и изменяет получателя на месте:

account = Account.new
# => #<Account id: nil, email: nil>
account.id = 1
account.reload
# Account Load (1.2ms)  SELECT "accounts".* FROM "accounts" WHERE "accounts"."id" = $1 LIMIT 1  [["id", 1]]
# => #<Account id: 1, email: 'account@example.com'>

Атрибуты перезагружаются из базы данных, и кэши очищаются, в частности, кэш ассоциаций.

Если запись больше не существует в базе данных ActiveRecord::RecordNotFound . В противном случае, помимо изменения на месте, метод возвращает self для удобства.

Необязательный флаг :lock позволяет заблокировать перезагруженную запись:

reload(lock: true) # reload with pessimistic locking

Перезагрузка часто используется в тестовых наборах, чтобы проверить, что что-то действительно записано в базу данных, или когда какое-либо действие изменяет соответствующую строку в базе данных, но не объект в памяти:

assert account.deposit!(25)
assert_equal 25, account.credit        # check it is updated in memory
assert_equal 25, account.reload.credit # check it is also persisted

Ещё один распространённый случай использования — обработка оптимистической блокировки:

def with_optimistic_retry
  begin
    yield
  rescue ActiveRecord::StaleObjectError
    begin
      # Reload lock_version in particular.
      reload
    rescue ActiveRecord::RecordNotFound
      # If the record is gone there is nothing to do.
    else
      retry
    end
  end
end
# File activerecord/lib/active_record/persistence.rb, line 387
def reload(options = nil)
  clear_aggregation_cache
  clear_association_cache

  fresh_object =
    if options && options[:lock]
      self.class.unscoped { self.class.lock(options[:lock]).find(id) }
    else
      self.class.unscoped { self.class.find(id) }
    end

  @attributes.update(fresh_object.instance_variable_get('@attributes'))

  @column_types           = self.class.column_types
  @column_types_override  = fresh_object.instance_variable_get('@column_types_override')
  @attributes_cache       = {}
  @new_record             = false
  self
end
save(*) Показать исходный код

Сохраняет модель.

Если модель новая, в базе данных создаётся запись, в противном случае существующая запись обновляется.

По умолчанию save всегда выполняет валидацию. Если какая-либо из них завершается неудачно, действие отменяется, и save возвращает false. Однако, если вы передадите validate: false, валидация будет пропущена. Дополнительные сведения см. в ActiveRecord::Validations.

Существует ряд обратных вызовов, связанных с save. Если любой из обратных вызовов before_* возвращает false, действие отменяется, и save возвращает false. Дополнительные сведения см. в ActiveRecord::Callbacks.

Атрибуты, помеченные как только для чтения, будут игнорироваться при обновлении записи.

# File activerecord/lib/active_record/persistence.rb, line 102
def save(*)
  create_or_update
rescue ActiveRecord::RecordInvalid
  false
end
save!(*) Показать исходный код

Сохраняет модель.

Если модель новая, в базе данных создаётся запись, в противном случае существующая запись обновляется.

При этом всегда выполняются проверки save!. Если какая-либо из них завершится неудачно, генерируется исключение ActiveRecord::RecordInvalid. См. ActiveRecord::Validations для получения дополнительной информации.

Существует ряд обратных вызовов, связанных с save!. Если любой из обратных вызовов before_* вернёт false, действие отменяется и генерируется исключение ActiveRecord::RecordNotSaved методом save!. См. ActiveRecord::Callbacks для получения более подробной информации.

Атрибуты, помеченные как только для чтения, будут игнорироваться при обновлении записи.

# File activerecord/lib/active_record/persistence.rb, line 124
def save!(*)
  create_or_update || raise(RecordNotSaved)
end
toggle(attribute) Показать исходный код

Присваивает attribute логическое отрицание attribute?. Таким образом, если предикат возвращает true, атрибут станет false. Этот метод напрямую переключает базовое значение без вызова метода-сеттера. Возвращает self.

# File activerecord/lib/active_record/persistence.rb, line 326
def toggle(attribute)
  self[attribute] = !send("#{attribute}?")
  self
end
toggle!(attribute) Показать исходный код

Обёртка над toggle, которая сохраняет запись. Этот метод отличается от своей версии без символа восклицательного знака тем, что он пропускает через него устанавливающее значение атрибута. Сохранение не подвержено проверкам валидации. Возвращает true, если запись была сохранена.

# File activerecord/lib/active_record/persistence.rb, line 335
def toggle!(attribute)
  toggle(attribute).update_attribute(attribute, self[attribute])
end
touch(name = nil) Показать исходный код

Сохраняет запись с обновлёнными атрибутами updated_at/on, установленным на текущее время. Обратите внимание, что проверки валидации не выполняются, и вызываются только обратные вызовы after_touch, after_commit и after_rollback. Если имя атрибута передано, этот атрибут обновляется вместе с атрибутами updated_at/on.

product.touch               # updates updated_at/on
product.touch(:designed_at) # updates the designed_at attribute and updated_at/on

Если используется вместе с belongs_to, то touch вызовет метод touch связанного объекта.

class Brake < ActiveRecord::Base
  belongs_to :car, touch: true
end

class Car < ActiveRecord::Base
  belongs_to :corporation, touch: true
end

# triggers @brake.car.touch and @brake.car.corporation.touch
@brake.touch

Обратите внимание, что touch необходимо использовать на сохранённом объекте, в противном случае будет выброшено исключение ActiveRecordError. Например:

ball = Ball.new
ball.touch(:updated_at)   # => raises ActiveRecordError
# File activerecord/lib/active_record/persistence.rb, line 435
def touch(name = nil)
  raise ActiveRecordError, "cannot touch on a new record object" unless persisted?

  attributes = timestamp_attributes_for_update_in_model
  attributes << name if name

  unless attributes.empty?
    current_time = current_time_from_proper_timezone
    changes = {}

    attributes.each do |column|
      column = column.to_s
      changes[column] = write_attribute(column, current_time)
    end

    changes[self.class.locking_column] = increment_lock if locking_enabled?

    changed_attributes.except!(*changes.keys)
    primary_key = self.class.primary_key
    self.class.unscoped.where(primary_key => self[primary_key]).update_all(changes) == 1
  else
    true
  end
end
update(attributes) Показать исходный код

Обновляет атрибуты модели из переданного хэша и сохраняет запись, всё это в рамках транзакции. Если объект невалиден, сохранение завершится неудачно и вернёт false.

# File activerecord/lib/active_record/persistence.rb, line 228
def update(attributes)
  # The following transaction covers any possible database side-effects of the
  # attributes assignment. For example, setting the IDs of a child collection.
  with_transaction_returning_status do
    assign_attributes(attributes)
    save
  end
end
Также алиасировано как: update_attributes
update!(attributes) Показать исходный код

Обновляет получатель так же, как и update, но вызывает save! вместо save, поэтому исключение генерируется, если запись невалидна.

# File activerecord/lib/active_record/persistence.rb, line 241
def update!(attributes)
  # The following transaction covers any possible database side-effects of the
  # attributes assignment. For example, setting the IDs of a child collection.
  with_transaction_returning_status do
    assign_attributes(attributes)
    save!
  end
end
Также алиасировано как: update_attributes!
update_attribute(name, value) Показать исходный код

Обновляет один атрибут и сохраняет запись. Это особенно полезно для булевых флагов существующих записей. Также обратите внимание, что:

  • Проверка валидации пропущена.

  • Вызываются обратные вызовы.

  • Столбец updated_at/updated_on обновляется, если такой столбец доступен.

  • Обновляются все атрибуты, которые изменены в этом объекте.

Этот метод генерирует исключение ActiveRecord::ActiveRecordError, если атрибут помечен как только для чтения.

# File activerecord/lib/active_record/persistence.rb, line 218
def update_attribute(name, value)
  name = name.to_s
  verify_readonly_attribute(name)
  send("#{name}=", value)
  save(validate: false)
end
update_attributes(attributes)
Псевдоним для: update
update_attributes!(attributes)
Псевдоним для: update!
update_column(name, value) Показать исходный код

Эквивалентно update_columns(name => value).

# File activerecord/lib/active_record/persistence.rb, line 253
def update_column(name, value)
  update_columns(name => value)
end
update_columns(attributes) Показать исходный код

Обновляет атрибуты напрямую в базе данных, выполняя SQL-запрос UPDATE, и устанавливает их в получателе:

user.update_columns(last_request_at: Time.current)

Это самый быстрый способ обновления атрибутов, так как он работает напрямую с базой данных, но учтите, что стандартные процедуры обновления полностью отключаются. В частности:

  • Проверки валидации пропускаются.

  • Обратные вызовы пропускаются.

  • updated_at/updated_on не обновляются.

Этот метод генерирует исключение ActiveRecord::ActiveRecordError, когда вызывается на новых объектах или когда хотя бы один из атрибутов помечен как только для чтения.

# File activerecord/lib/active_record/persistence.rb, line 272
def update_columns(attributes)
  raise ActiveRecordError, "cannot update on a new record object" unless persisted?

  attributes.each_key do |key|
    verify_readonly_attribute(key.to_s)
  end

  updated_count = self.class.unscoped.where(self.class.primary_key => id).update_all(attributes)

  attributes.each do |k, v|
    raw_write_attribute(k, v)
  end

  updated_count == 1
end

© 2004–2016 David Heinemeier Hansson
Licensed under the MIT License.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API