Spec-Zone.ru › Ruby on Rails 4.2

модуль ActiveRecord::Persistence

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

Открытые методы экземпляров

becomes(klass) Показать исходный код
# File activerecord/lib/active_record/persistence.rb, line 198
def becomes(klass)
  became = klass.new
  became.instance_variable_set("@attributes", @attributes)
  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

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

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

becomes!(klass) Показать исходный код
# File activerecord/lib/active_record/persistence.rb, line 215
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

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

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

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

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

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

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

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

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

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

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

destroy() Показать исходный код
# File activerecord/lib/active_record/persistence.rb, line 168
def destroy
  raise ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly?
  destroy_associations
  self.class.connection.add_transaction_record(self)
  destroy_row if persisted?
  @destroyed = true
  freeze
end

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

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

destroy!() Показать исходный код
# File activerecord/lib/active_record/persistence.rb, line 184
def destroy!
  destroy || raise(RecordNotDestroyed.new("Failed to destroy the record", self))
end

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

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

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

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

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

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

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

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

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

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

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

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

reload(options = nil) Показать исходный код
# File activerecord/lib/active_record/persistence.rb, line 407
def reload(options = nil)
  clear_aggregation_cache
  clear_association_cache
  self.class.connection.clear_query_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 = fresh_object.instance_variable_get('@attributes')
  @new_record = false
  self
end

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

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

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
save(*) Показать исходный код
# File activerecord/lib/active_record/persistence.rb, line 119
def save(*)
  create_or_update
rescue ActiveRecord::RecordInvalid
  false
end

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

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

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

Существует ряд колбэков, связанных с save. Если какой-либо из колбэков before_* возвращает false, действие отменяется, и save возвращает false. Подробнее см. ActiveRecord::Callbacks.

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

save!(*) Показать исходный код
# File activerecord/lib/active_record/persistence.rb, line 141
def save!(*)
  create_or_update || raise(RecordNotSaved.new("Failed to save the record", self))
end

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

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

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

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

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

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

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

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

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

touch(*names) Показать исходный код
# File activerecord/lib/active_record/persistence.rb, line 455
def touch(*names)
  raise ActiveRecordError, "cannot touch on a new record object" unless persisted?

  attributes = timestamp_attributes_for_update_in_model
  attributes.concat(names)

  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?

    clear_attribute_changes(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

Сохраняет запись с обновлёнными атрибутами 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
product.touch(:started_at, :ended_at) # updates started_at, ended_at and updated_at/on attributes

Если используется вместе с 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
update(attributes) Показать исходный код
# File activerecord/lib/active_record/persistence.rb, line 247
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

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

Также алиас: update_attributes
update!(attributes) Показать исходный код
# File activerecord/lib/active_record/persistence.rb, line 260
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, но вызывает save! вместо save, поэтому исключение генерируется, если запись невалидна.

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

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

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

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

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

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

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

См. также update_column.

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

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

update_columns(attributes) Показать исходный код
# File activerecord/lib/active_record/persistence.rb, line 291
def update_columns(attributes)
  raise ActiveRecordError, "cannot update a new record" if new_record?
  raise ActiveRecordError, "cannot update a destroyed record" if destroyed?

  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

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

user.update_columns(last_request_at: Time.current)

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

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

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

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

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

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

Spec-Zone.ru

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