Spec-Zone.ru › Ruby on Rails 5.0

класс ActiveRecord::Base

Родитель:
Объект
Включенные модули:
ActiveRecord::Core, ActiveRecord::Persistence, ActiveRecord::ReadonlyAttributes, ActiveRecord::ModelSchema, ActiveRecord::Inheritance, ActiveRecord::Scoping, ActiveRecord::Sanitization, ActiveRecord::AttributeAssignment, ActiveModel::Conversion, ActiveRecord::Integration, ActiveRecord::Validations, ActiveRecord::CounterCache, ActiveRecord::Attributes, ActiveRecord::Locking::Optimistic, ActiveRecord::Locking::Pessimistic, ActiveRecord::AttributeMethods, ActiveRecord::Callbacks, ActiveRecord::Timestamp, ActiveRecord::Associations, ActiveModel::SecurePassword, ActiveRecord::AutosaveAssociation, ActiveRecord::NestedAttributes, ActiveRecord::Aggregations, ActiveRecord::Transactions, ActiveRecord::TouchLater, ActiveRecord::NoTouching, ActiveRecord::Reflection, ActiveRecord::AttributeMethods::Serialization, ActiveRecord::Store, ActiveRecord::SecureToken, ActiveRecord::Suppressor

Active Record

Объекты Active Record не указывают свои атрибуты напрямую, а вместо этого выводят их из определения таблицы, с которой они связаны. Добавление, удаление и изменение атрибутов и их типа выполняется непосредственно в базе данных. Любое изменение немедленно отражается в объектах Active Record. Сопоставление, связывающее определенный класс Active Record с определенной таблицей базы данных, происходит автоматически в большинстве обычных случаев, но может быть переопределено в необычных.

См. правила сопоставления в таблице table_name и полный пример в files/activerecord/README_rdoc.html для более подробного понимания.

Создание

Active Record принимает параметры конструктора либо в виде хэша, либо в виде блока. Метод хэша особенно полезен, когда вы получаете данные из другого места, например, из запроса HTTP. Он работает так:

user = User.new(name: "David", occupation: "Code Artist")
user.name # => "David"

Вы также можете использовать инициализацию с блоком:

user = User.new do |u|
  u.name = "David"
  u.occupation = "Code Artist"
end

И, конечно же, вы можете просто создать пустой объект и указать атрибуты позже:

user = User.new
user.name = "David"
user.occupation = "Code Artist"

Условия

Условия могут быть указаны в виде строки, массива или хэша, представляющих часть WHERE SQL-запроса. Формат массива следует использовать, когда входные данные условия являются загрязнёнными и требуют очистки. Формат строки может быть использован для запросов, не включающих загрязнённые данные. Формат хэша работает очень похоже на формат массива, за исключением того, что возможны только операции равенства и диапазона. Примеры:

class User < ActiveRecord::Base
  def self.authenticate_unsafely(user_name, password)
    where("user_name = '#{user_name}' AND password = '#{password}'").first
  end

  def self.authenticate_safely(user_name, password)
    where("user_name = ? AND password = ?", user_name, password).first
  end

  def self.authenticate_safely_simply(user_name, password)
    where(user_name: user_name, password: password).first
  end
end

Метод authenticate_unsafely вставляет параметры непосредственно в запрос и, следовательно, уязвим к атакам SQL-инъекции, если параметры user_name и password получены непосредственно из запроса HTTP. Методы authenticate_safely и authenticate_safely_simply очистят параметры user_name и password перед их вставкой в запрос, что гарантирует, что злоумышленник не сможет обойти запрос и подделать вход (или что-то худшее).

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

Company.where(
  "id = :id AND name = :name AND division = :division AND created_at > :accounting_date",
  { id: 3, name: "37signals", division: "First", accounting_date: '2005-01-01' }
).first

Аналогично, простой хэш без инструкции сгенерирует условия, основанные на равенстве с оператором SQL AND. Например:

Student.where(first_name: "Harvey", status: 1)
Student.where(params[:student])

Диапазон может быть использован в хэше для использования оператора SQL BETWEEN:

Student.where(grade: 9..12)

Массив может быть использован в хэше для использования оператора SQL IN:

Student.where(grade: [9,11,12])

При объединении таблиц могут быть использованы вложенные хэши или ключи в форме 'имя_таблицы.имя_столбца' для квалификации имени таблицы конкретного условия. Например:

Student.joins(:schools).where(schools: { category: 'public' })
Student.joins(:schools).where('schools.category' => 'public' )

Переопределение стандартных аксессоров

Все значения столбцов автоматически доступны через базовые аксессоры объекта Active Record, но иногда вам необходимо специализировать это поведение. Это можно сделать, переопределив стандартные аксессоры (используя то же имя, что и атрибут) и вызвав super для фактического изменения.

class Song < ActiveRecord::Base
  # Uses an integer of seconds to hold the length of the song

  def length=(minutes)
    super(minutes.to_i * 60)
  end

  def length
    super / 60
  end
end

Методы запроса атрибутов

Помимо базовых аксессоров, методы запроса также автоматически доступны в объекте Active Record. Методы запроса позволяют проверить, существует ли значение атрибута. Кроме того, при работе с числовыми значениями метод запроса вернёт false, если значение равно нулю.

Например, у объекта Active Record User с атрибутом name есть метод name?, который можно вызвать, чтобы определить, есть ли у пользователя имя:

user = User.new(name: "David")
user.name? # => true

anonymous = User.new(name: "")
anonymous.name? # => false

Доступ к атрибутам до их приведения к типу

Иногда вам нужно получить данные атрибута в исходном виде, не дожидаясь приведения к типу, определённому столбцом. Это можно сделать с помощью аксессоров <attribute>_before_type_cast для всех атрибутов. Например, если в модели Account есть атрибут balance, вы можете вызвать account.balance_before_type_cast или account.id_before_type_cast.

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

Динамические поисковые методы, основанные на атрибутах

Динамические поисковые методы, основанные на атрибутах, — это слабо устаревший способ получения (и/или создания) объектов с помощью простых запросов без обращения к SQL. Они работают путём добавления имени атрибута к find_by_, как в Person.find_by_user_name. Вместо написания Person.find_by(user_name: user_name), вы можете использовать Person.find_by_user_name(user_name).

Можно добавить восклицательный знак (!) в конце динамических поисковых методов, чтобы они вызывали ошибку ActiveRecord::RecordNotFound, если они не возвращают записи, например, Person.find_by_last_name!.

Также можно использовать несколько атрибутов в одном find_by_, разделяя их символом «и».

Person.find_by(user_name: user_name, password: password)
Person.find_by_user_name_and_password(user_name, password) # with dynamic finder

Эти динамические методы поиска можно применять и к отношениям, и к именованным объёмам.

Payment.order("created_on").find_by_amount(50)

Сохранение массивов, хэшей и других не отображаемых объектов в текстовых столбцах

Active Record может сериализовать любой объект в текстовых столбцах с помощью YAML. Для этого необходимо указать это с помощью вызова метода класса serialize. Это позволяет сохранять массивы, хэши и другие не отображаемые объекты без дополнительных действий.

class User < ActiveRecord::Base
  serialize :preferences
end

user = User.create(preferences: { "background" => "black", "display" => large })
User.find(user.id).preferences # => { "background" => "black", "display" => large }

Вы также можете указать параметр класса в качестве второго параметра, который вызовет исключение, если сериализованный объект получен как потомок класса, отсутствующего в иерархии.

class User < ActiveRecord::Base
  serialize :preferences, Hash
end

user = User.create(preferences: %w( one two three ))
User.find(user.id).preferences    # raises SerializationTypeMismatch

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

class User < ActiveRecord::Base
  serialize :preferences, OpenStruct
end

user = User.new
user.preferences.theme_color = "red"

Единотабличная наследование

Active Record позволяет наследование, сохраняя имя класса в столбце, который по умолчанию называется «type». См. ActiveRecord::Inheritance для получения дополнительной информации.

Подключение к нескольким базам данных в разных моделях

Подключения обычно создаются с помощью ActiveRecord::Base.establish_connection и извлекаются с помощью ActiveRecord::Base.connection. Все классы, унаследованные от ActiveRecord::Base, будут использовать это подключение. Но вы также можете установить подключение, специфичное для класса. Например, если Course — это ActiveRecord::Base, но находится в другой базе данных, вы можете просто сказать Course.establish_connection и Course, и все его подклассы будут использовать это подключение вместо текущего.

Эта функция реализована путём хранения пула подключений в ActiveRecord::Base, который является хэшем, индексированным по классу. Если запрос на подключение, метод ActiveRecord::Base.retrieve_connection будет подниматься по иерархии классов, пока не найдёт подключение в пуле подключений.

Исключения

  • ActiveRecordError — универсальный класс ошибок и суперкласс всех остальных ошибок, генерируемых Active Record.

  • AdapterNotSpecified — в хэш конфигурации, используемой в ActiveRecord::Base.establish_connection, не был включён ключ :adapter.

  • AdapterNotFound — ключ :adapter, используемый в ActiveRecord::Base.establish_connection, указал на несуществующий адаптер (или неправильное написание существующего).

  • AssociationTypeMismatch — объект, назначенный ассоциации, не был того типа, который указан в определении ассоциации.

  • AttributeAssignmentError — произошла ошибка во время массового назначения через метод ActiveRecord::Base#attributes=. Вы можете просмотреть свойство attribute объекта исключения, чтобы определить, какой атрибут вызвал ошибку.

  • ConnectionNotEstablished — подключение не установлено. Используйте ActiveRecord::Base.establish_connection перед запросом.

  • MultiparameterAssignmentErrors — набор ошибок, возникших во время массового назначения с помощью метода ActiveRecord::Base#attributes=. Свойство errors этого исключения содержит массив объектов AttributeAssignmentError, которые следует проверить, чтобы определить, какие атрибуты вызвали ошибки.

  • RecordInvalid — генерируется методами ActiveRecord::Base#save! и ActiveRecord::Base.create!, когда запись некорректна.

  • RecordNotFound — ни одна запись не ответила на метод ActiveRecord::Base.find. Либо строка с заданным идентификатором не существует, либо строка не удовлетворяла дополнительным ограничениям. Некоторые вызовы ActiveRecord::Base.find не генерируют это исключение, чтобы указать, что ничего не найдено. Пожалуйста, проверьте документацию для получения дополнительной информации.

  • SerializationTypeMismatch — сериализованный объект не был класса, указанного как второй параметр.

  • StatementInvalid — сервер базы данных отклонил SQL-запрос. Точная ошибка указана в сообщении.

Примечание: Перечисленные атрибуты являются атрибутами на уровне класса (доступны как на уровне класса, так и на уровне экземпляра). Поэтому можно назначить логгер классу через Base.logger=, который затем будет использоваться всеми экземплярами в текущем пространстве объектов.

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

Spec-Zone.ru

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