class ActiveRecord::Base
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
Методы запроса также будут учитывать любые переопределения стандартных аксессоров:
class User
# Has admin boolean column
def admin
false
end
end
user.update(admin: true)
user.read_attribute(:admin) # => true, gets the column value
user[:admin] # => true, also gets the column value
user.admin # => false, due to the getter overwrite
user.admin? # => false, due to the getter overwrite
Доступ к атрибутам до их приведения к типу
Иногда необходимо прочитать данные атрибута в сыром виде, не дожидаясь приведения к типу, определённого столбцом. Это можно сделать с помощью аксессоров <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. Либо строка с заданным ID не существует, либо строка не удовлетворяет дополнительным ограничениям. Некоторые вызовы ActiveRecord::Base.find не поднимают это исключение для сигнализации об отсутствии ничего, пожалуйста, проверьте его документацию для получения дополнительной информации. -
SerializationTypeMismatch– Сериализованный объект не был того класса, который был указан в качестве второго параметра. -
StatementInvalid– Сервер базы данных отклонил SQL-запрос. Точная ошибка указана в сообщении.
Примечание: Перечисленные атрибуты являются атрибутами уровня класса (доступны как с уровня класса, так и с уровня экземпляра). Поэтому можно назначить логгер классу через Base.logger=, который затем будет использоваться всеми экземплярами в текущем пространстве объектов.
© 2004–2021 David Heinemeier Hansson
Licensed under the MIT License.