В прошлом для создания веб-приложения требовались навыки написания кода на языке бизнес-логики и языке базы данных. Однако в последнее время серверные инфраструктуры склоняются к использованию объектно-реляционного сопоставления (ORM); Это метод, который позволяет вам управлять базой данных на языке бизнес-логики, который вам наиболее удобен.
Rails использует ORM в форме Active Record. В этом уроке мы погрузимся в Active Record и посмотрим, что он может сделать для нас!
Что такое активная запись, именно
Как я уже сказал, Active Record — это ORM. Это означает, что это слой кода Ruby, который выполняется между вашей базой данных и вашим логическим кодом. Когда вам нужно внести изменения в базу данных, вы напишите код Ruby, а затем запустите миграцию, которую мы вскоре рассмотрим. Эти миграции вносят реальные изменения в базу данных. Самое интересное в том, что не имеет значения, какую базу данных вы используете: Rails может обрабатывать почти все из них. Например, Rails использует SQLite локально при разработке. Однако предположим, что вы развертываете на Heroku, который использует PostreSQL. Все, что вам нужно сделать, это добавить это в ваш Gemfile
:
1
2
3
|
group :production do
gem ‘pg’
end
|
Теперь при развертывании Heroku выполнит те же самые миграции (используя адаптер PostgreSQL). Тот же код, другая база данных, что довольно круто, на мой взгляд.
Итак, вот что такое Active Record; давайте копать глубже и посмотрим, как все это работает.
Начиная
Хотя технически возможно использовать Active Record вне приложения Rails, в девяти случаях из десяти вы будете использовать его в приложении Rails, так что именно это мы и сделаем здесь. Я использую Rails 3.2.12, последнюю версию, когда я печатаю это. Если вы установили это, вы можете начать с создания нового приложения Rails.
1
2
|
rails new myapp
cd myapp
|
Теперь мы можем начать с создания модели.
Создание моделей и миграций
Как и следовало ожидать, поскольку Active Record взаимодействует с базой данных, это MVC- модели M в Rails. Из командной строки мы создадим модель, скажем, для человека. На самом деле команда rails generate
довольно гибкая: все следующие команды работают:
1
2
3
|
rails generate model Person
rails g model Person
rails g model Person first_name last_name age:integer
|
Первые две строки здесь делают то же самое; rails g
— это просто ярлык для rails generate
. Третий дает Rails немного больше информации, поэтому он может сделать немного больше для нас. Мы говорим, что хотим, чтобы в этой модели было три поля: first_name
, last_name
и age
. Для first_name
и last_name
мы не указываем тип, поэтому по умолчанию используется строка. Для age
мы говорим, что оно должно быть целым числом.
Итак, что это на самом деле делать? Вы должны увидеть некоторые результаты, объясняющие это. Важные биты это:
1
2
|
create db/migrate/20130213204626_create_people.rb
create app/models/person.rb
|
Первый файл — это ваш файл миграции (конечно, метка времени будет другой); второй — ваш класс по Ruby.
Вам должно быть удобно с синтаксисом файла миграции, потому что вам часто нужно корректировать код. Давайте проверим это.
01
02
03
04
05
06
07
08
09
10
11
|
class CreatePeople < ActiveRecord::Migration
def change
create_table :people do |t|
t.string :first_name
t.string :last_name
t.integer :age
[ruby] t.timestamps
end
end
end
|
Каждая миграция является классом; у этого есть единственный метод: change
. Если вы знакомы с Ruby, это должно быть самоочевидным: эта миграция создает таблицу с именем «people» в базе данных. Эта таблица имеет шесть столбцов. Это верно, шесть. Есть поля first_name
, last_name
и age
мы добавили из командной строки; в блоке create_table
мы используем методы, названные в честь типа данных, и передаем им символ с именем столбца.
Тогда есть t.timestamps
. Это создает еще две колонки в нашей таблице: created_at
и updated_at
. Конечно, они имеют тип datetime
(подробнее о ваших типах позже). Active Record заботится об этих полях на протяжении всей жизни ваших записей, устанавливая и обновляя их при необходимости.
Шестой и последний столбец — это id
, который здесь не указан, потому что он добавлен по умолчанию. Это уникальный первичный ключ для таблицы.
Создание таблиц — только одно использование для класса миграции; помните, это ваш метод настройки базы данных, поэтому они могут выполнять любую работу с базой данных, которая вам когда-либо может понадобиться. Но одна из важных идей, связанных с миграцией, заключается в том, что вы можете откатить их назад или отменить их последствия. Это означает, что у каждого класса миграции должно быть достаточно информации, чтобы отменить ее последствия. Несколько методов могут «отменить себя»; например, противоположность добавления таблицы — ее удаление, которая не требует никакой дополнительной информации. Вот почему мы можем использовать метод change
здесь. Однако, если мы делаем что-то, что не может быть автоматически отменено, мы должны указать действия для выполнения и отмены нашей миграции. В этих случаях наш класс миграции должен иметь два метода: up
и down
. Метод up
подробно расскажет, что делать при запуске миграции, а метод down
объяснит, как откатить миграцию.
Давайте напишем нашу собственную миграцию с нуля, чтобы попробовать эту функцию отката. Начнем с создания пустой миграции:
1
|
rails g migration do_stuff
|
(Обычно вы дадите своей миграции разумное имя.)
Теперь мы можем открыть db/migrate/<timestamp>_do_stuff.rb
. По умолчанию у него будут методы up
/ down
, но сделайте это заранее и замените его одним методом change
.
1
2
3
4
5
6
7
8
9
|
class DoStuff < ActiveRecord::Migration
def change
create_table :nothing do |t|
t.string :blank
end
[ruby] add_column :people, :job, :string
end
end
|
Мы начнем с создания бесполезной таблицы, с синтаксисом, аналогичным таблице выше. Затем мы используем метод add_column
для добавления столбца в таблицу people: в частности, столбец job
типа string. Оба эти действия можно легко отменить, опустив таблицу и удалив столбец.
Теперь давайте запустим две наши миграции. Мы делаем это через грабли:
1
|
rake db:migrate
|
Вы должны увидеть результат примерно так:
01
02
03
04
05
06
07
08
09
10
11
|
== CreatePeople: migrating =====================
— create_table(:people)
-> 0.0027s
== CreatePeople: migrated (0.0034s) ============
== DoStuff: migrating ==========================
— create_table(:nothing)
-> 0.0014s
— add_column(:people, :job, :string)
-> 0.0008s
== DoStuff: migrated (0.0037s) =================
|
Вы можете увидеть из вывода именно то, что было сделано. Первая миграция создала таблицу people
; второй создал таблицу « nothing
и добавил столбец. Теперь давайте отменим последнюю миграцию, которую мы запустили. Мы можем сделать это, выполнив следующее:
1
|
rake db:rollback
|
Опять же, вывод подтверждает:
1
2
3
4
5
6
|
== DoStuff: reverting ==========================
— remove_column(«people», :job)
-> 0.0134s
— drop_table(«nothing»)
-> 0.0004s
== DoStuff: reverted (0.0140s) =================
|
И теперь миграция, которую мы написали с нуля, была отменена.
Важное замечание: если вы относительно новичок в Rails, вы можете забыть, что миграции не запускаются автоматически при создании новой модели. Вы должны запустить их вручную. Да, я забыл об этом довольно много раз и задавался вопросом, что происходит, только чтобы понять, что стола, с которым я пытался работать, еще не было.
Помимо create_table
и add_column
, существует множество других методов, которые вы можете использовать в своих файлах миграции. Мы не можем вдаваться в подробности этого руководства, но если они выглядят так, как вам нужно, ознакомьтесь с документацией по миграции .
-
add_column
-
add_index
-
add_timestamps
-
change_column
-
change_table
-
create_table
-
drop_table
-
remove_column
-
remove_index
-
remove_timestamps
-
rename_column
-
rename_index
-
rename_table
Последнее замечание по миграции: вот список поддерживаемых типов, которые вы можете использовать в своих классах миграции:
-
binary
-
boolean
-
date
-
datetime
-
decimal
-
float
-
integer
-
primary_key
-
string
-
text
-
time
-
timestamp
Глядя на класс Active Record
Теперь, когда мы настроили базу данных, мы готовы взглянуть на другую часть нашей модели: класс Active Record. Это та часть, с которой вы на самом деле будете взаимодействовать со своими контроллерами Rails. Когда мы создали модель Person
, был создан файл app/models/person.rb
; это выглядит так:
1
2
3
|
class Person < ActiveRecord::Base
attr_accessible :age, :first_name, :last_name
end
|
Если вы уже работали с Ruby, возможно, вы знакомы с методом attr_accessor
, который создает методы getter и setter для рассматриваемых атрибутов. Ну, метод attr_accessible
другой; это на самом деле специфично для Rails. Любые свойства, которые являются attr_accessible
-ized, могут быть установлены посредством массового присваивания Это просто означает одновременную установку нескольких свойств объекта; это часто делается при создании объекта, например:
1
|
Person.new first_name: «Andrew», last_name: «Burgess», age: 22
|
Каждое из свойств, определенных с помощью attr_accessible
должно быть одним из полей, которые мы определили в наших таблицах базы данных, в наших миграциях (есть несколько исключений из этого). Но это не значит, что все наши свойства должны быть определены как доступные; могут быть некоторые свойства, которые вы хотите установить более намеренно; например, свойство admin
которое дает административные привилегии пользовательской записи, вероятно, не должно быть разрешено при массовом назначении, где оно может быть установлено случайно / злонамеренно.
Для простых классов Active Record attr_accessible
только эта строка свойств attr_accessible
. На самом деле мы можем добавить к нашему классу модели намного больше, чтобы сделать его более надежным, но давайте сначала рассмотрим эту модель Person в обе стороны и посмотрим, как создавать экземпляры модели.
Создание записей
В «Обычном дне в жизни приложения Rails» все записи базы данных будут созданы в контроллере. Однако в этом уроке мы будем использовать консоль Rails. В терминале вы можете открыть консоль Rails, выполнив одно из следующих действий:
1
2
|
rails console
rails c
|
Это открывает консоль Ruby, в которой вы можете использовать все ваши классы Model.
Как вы видели выше, мы можем создать новые записи базы данных, создав экземпляр класса:
1
2
|
p = Person.new first_name: «John», last_name: «Doe», age: 30
#=> #<Person id: nil, first_name: «John», last_name: «Doe», age: 30, created_at: nil, updated_at: nil>
|
Вторая строка — это значение нашей переменной p
: новый объект Person
. Обратите внимание, что три из шести свойств были установлены, а остальные три — нет. Они будут установлены, когда запись будет сохранена в базе данных, которой на данный момент не является (если вы ввели exit
прямо сейчас, в базе данных ничего не будет сохранено). Вы можете подтвердить, что он не сохранен, запустив
1
2
|
p.new_record?
#=> true
|
Чтобы сохранить запись в базе данных, вы можете вызвать метод save
:
1
|
p.save
|
Обратите внимание на эту часть вывода:
1
|
INSERT INTO «people» («age», «created_at», «first_name», «last_name», «updated_at») VALUES (?, ?, ?, ?, ?) [[«age», 30], [«created_at», Fri, 15 Feb 2013 16:02:18 UTC +00:00], [«first_name», «John»], [«last_name», «Doe»], [«updated_at», Fri, 15 Feb 2013 16:02:18 UTC +00:00]]
|
Да, это оператор SQL. Помните, что Active Record использует API базы данных, поэтому SQL по-прежнему нужно выполнять. Это одна из особенностей консоли Rails: вы можете поэкспериментировать с различными методами Active Record и точно увидеть, как они касаются базы данных. Это будет полезно, когда вы запускаете методы, которые извлекают много данных, возможно, из нескольких таблиц: вы можете выбрать правильные методы для получения наиболее эффективного запроса SQL.
Но теперь, посмотрите нашу запись
1
2
3
4
|
p.new_record?
#=> false
p
#=> #<Person id: 1, first_name: «John», last_name: «Doe», age: 30, created_at: «2013-02-15 16:02:18», updated_at: «2013-02-15 16:02:18»>
|
Поля id
, created_at
и updated_at
установлены.
Если вы хотите, вы можете создать и сохранить новую запись сразу, с помощью метода create
:
1
2
3
4
|
p2 = Person.create first_name: «Jane», last_name: «Doe», age: 25
#=> #<Person id: 2, first_name: «Jane», last_name: «Doe», age: 25, created_at: «2013-02-15 16:26:42», updated_at: «2013-02-15 16:26:42»>
p2.new_record?
#=> false
|
При работе с отдельными записями вы можете устанавливать или изменять любые свойства, используя их отдельные методы; просто помните, что установка свойства не сохраняет его в базе данных; это требует save
вызова.
1
2
|
p2.first_name = «Janice»
p2.save
|
Если вы хотите обновить несколько атрибутов одновременно, вы можете использовать update_attributes
, который принимает хеш всех атрибутов, которые вы хотите изменить:
1
|
p.update_attributes first_name: «Jonathan», last_name: «Doherty»
|
Важным отличием в update_attributes
является то, что save
запускается внутри этого метода; нет необходимости сохранять изменения самостоятельно.
Как я уже сказал, мы можем сделать больше в модельном классе. Итак, давайте вернемся и посмотрим на некоторые из этих других функций.
Validations
Проверки являются важной частью любого веб-приложения; Здесь мы гарантируем, что данные, которые мы помещаем в базу данных, чистые и правильные.
Прежде чем мы начнем, важно понять, что правила проверки, созданные в ваших модельных классах, не изменяют действительную базу данных. Например, говоря, что указанное свойство обязательно в вашем классе модели, не делает его обязательным на уровне базы данных (такого рода вещи, которые вы бы задали в своих — подождите это — миграциях). Вам не о чем беспокоиться, я просто хочу убедиться, что вы понимаете общую картину здесь.
Так. Validations. В текущих версиях Rails мы используем метод validates
для настройки всех наших проверок (это было в прошлом). Сначала мы передаем ему поле или поля, которые мы проверяем. Затем мы можем передать ему хэш свойств проверки. Есть куча этих помощников проверки (как они называются), которые мы можем использовать; Вот несколько, которые вы будете использовать постоянно.
Вероятно, наиболее распространенным является просто проверка того, что данное поле заполнено; для этого мы делаем проверку presence
:
1
|
validates :first_name, :last_name, presence: true
|
Здесь мы last_name
атрибуты first_name
и last_name
. В нашем хэше свойств проверки мы устанавливаем presence
в true, что означает, что эти атрибуты не должны быть nil
при сохранении записи.
Еще одна распространенная проверка — убедиться, что поле уникально. Мы можем сделать это с помощью помощника по уникальности.
1
|
validates :username, uniqueness: true
|
Несколько помощников проверки не просто принимают true
или false
; им нужно еще несколько вариантов. На самом деле, помощник уникальности является одним из них; когда мы просто устанавливаем значение true
, как указано выше, чувствительность к регистру включена. Правда, с именами пользователей bob
и BOB
должны быть одинаковыми. Итак, мы должны сделать это:
1
|
validates :username, uniqueness: { case_sensitive: false }
|
Теперь bob
и BOB
будут считаться одинаковыми.
Иногда вы хотите, чтобы свойство было одним из заданного набора параметров. Попробуйте inclusion
, который принимает массив (или любой другой перечисляемый объект).
1
|
validates :account, inclusion: [‘free’, ‘premium’, ‘business’]
|
Противоположностью inclusion
является exclusion
, которое гарантирует, что значение поля не входит в данный набор:
1
|
validates :appt_day, exclusion: [‘Sunday’, ‘Saturday’]
|
Если вы хотите убедиться, что поле имеет заданную длину? Введите length
. Есть несколько способов использовать этот. Вот пара примеров:
1
2
3
|
validates :username, length: { maximum: 15 }
validates :first_name, length: { minimum: 1}
validates :password, length: { in:10..50 }
|
Вы даже можете установить пороги:
1
2
|
validates :age, length: { greater_than: 18 }
validates :commission_percentage, length: { less_than: 30 }
|
Возможно, вы захотите подтвердить, что значение является числом. Для этого используйте numericality
:
1
|
validates :price, numericality: true
|
numericality
также может обрабатывать политику «без десятичных знаков»:
1
|
validates :year, numericality: { only_integers: true }
|
Последнее, что я покажу вам, это format
, который позволит вам установить регулярное выражение для поля, которое будет соответствовать:
1
2
|
# not a real email regex
validates :email, format: { with: /\w_@\w_.\w*/ }
|
Есть несколько других, но это поможет вам начать. Последний кусочек: вы можете создавать свои собственные вспомогательные классы проверки. Проверьте документацию для деталей об этом.
Есть несколько общих опций, которые подходят почти для всех помощников валидации. Во-первых, мы можем установить allow_nil
чтобы позволить свойству быть незаполненным.
1
|
validates :nickname, length: { in: 4..10, allow_nil: true }
|
Если пустая строка является приемлемой, вы можете использовать allow_blank
.
Более распространенным является message
; если проверка не пройдена, к объекту будет прикреплено сообщение (подробнее об этом позже). Конечно, все помощники проверки имеют сообщения по умолчанию, но вы можете установить свое собственное message
.
1
|
validates :year, presence: true, message: «Please select a year.»
|
Последнее, о котором я упомяну, — это то, что решает, на каких условиях будет выполняться проверка. Значения могут быть :create
(проверка выполняется только при сохранении новых записей). :update
(он запускается только при сохранении ранее сохраненных записей) или :save
(он запускается в обоих случаях). Конечно, по умолчанию :save
.
1
|
validates :password, length: { in: 10..20, on: :create }
|
Ошибки валидации
Метод save
экземпляра модели возвращает true
если он был успешно сохранен, и false
если это не так. Если вы получите false
реакцию, вы захотите узнать, какие были ошибки, верно?
Экземпляр вашей модели имеет свойство error
, которое является экземпляром ActiveModel::Errors
. После запуска проверок этот объект заполняется всеми сообщениями об ошибках для неудачных проверок; они хранятся в своих собственных messages
. Заметим:
1
2
3
4
5
6
7
|
p = Person.new
p.save # false
p.errors.messages
# {:first_name=>[«can’t be blank»], :last_name=>[«can’t be blank»], :age=>[«can’t be blank», «is not a number»]}
# alternatively:
p.errors.full_messages
# [«First name can’t be blank», «Last name can’t be blank», «Age can’t be blank», «Age is not a number»]
|
Обычно вы хотите отобразить эти ошибки пользователю, возможно, рядом с формой, которую они отправили. Один из самых простых способов сделать это — full_messages
свойство full_messages
из вашего блока form_for
и распечатать их в виде списка или чего-то еще. Еще проще — позволить Rails обрабатывать всю эту разметку, запустив form.error_messages
.
Callbacks
Обратные вызовы — еще одна интересная часть Active Record; они позволяют вам запускать пользовательские методы в указанное время. Если вы прочитали мое руководство по Building Ribbit in Rails , вы, возможно, помните, что мы использовали before_save
вызов before_save
чтобы установить свойство avatar_hash
для пользователей перед их сохранением. Сначала мы создаем метод, который мы хотим запустить:
1
2
3
|
def create_avatar_hash
self.avatar_hash = «http://www.gravatar.com/avatar/#{Digest::MD5.hexdigest(self.email)}?s=50»
end
|
И тогда мы просто регистрируем обратный вызов:
1
|
before_save :create_avatar_hash
|
Это означает, что когда мы вызываем save
, наш метод будет запущен непосредственно перед тем, как сохранение будет выполнено.
Мы также использовали before_validation
вызов before_validation
для удаления и уменьшения адреса электронной почты. Хотя это только два из обратных вызовов, которые вы можете использовать, они являются хорошими примерами таких обратных вызовов, которые могут быть полезны. Вот другие:
-
before_validation
/after_validation
-
before_save
/around_save
/after_save
-
before_create
/around_create
/after_create
-
before_update
/around_update
/after_update
-
before_destroy
/around_destroy
/after_destroy
around_*
знать о around_*
? Это довольно круто. Они вызываются до того, как действие выполнено, но затем вы можете выполнить действие из метода, вызвав yield
. Когда действие выполнено, выполняется сброс метода обратного вызова. Круто, а?
ассоциации
Большинство реляционных баз данных имеют несколько таблиц, которые каким-то образом связаны, поэтому вполне естественно, что Active Record сможет справиться с этим: это происходит посредством ассоциаций Active Record. Допустим, мы хотим, чтобы в нашей базе данных была таблица заказов, и чтобы у каждого сотрудника было несколько заказов. Как это настроить?
Мы должны начать с создания нашей модели Order
:
1
|
rails g model Order total:integer person_id:integer
|
Важной частью здесь является поле person_id
; как и следовало ожидать, это будет наш внешний ключ, связь между двумя классами. Мы называем это person_id
потому что, как только мы person_id
нашим модельным классам об отношениях, класс Order
по умолчанию будет искать поле с этим именем. Если бы мы хотели назвать это как-то иначе, например orderer_identifier
, нам пришлось бы сказать Order
что поле не названо в честь класса, к которому оно подключается. Проще перейти с настройками по умолчанию.
Миграция, созданная этой командой, будет всем, что нам нужно, поэтому я перенесу ее сейчас:
1
|
rake db:migrate
|
Теперь нам нужно проинформировать классы об отношениях. Внутри app/model/person.rb
добавьте эту строку:
1
|
has_many :orders
|
Теперь в app/model/order.rb
добавьте это:
1
|
belongs_to :person
|
Person
мы говорим, что может быть много заказов для каждой записи человека; по-разному, у каждого человека есть много заказов. И наоборот, каждый заказ belongs_to
экземпляру лица. Они просто добавляют несколько удобных методов для наших экземпляров Person
и Order
, которые мы увидим чуть позже.
Итак, давайте проверим эти отношения, не так ли? В консоли Rails:
1
2
3
4
5
6
|
p = Person.find(1)
o = Order.new total: 100
o.person = p
o.save
p.orders
#=> [#<Order id: 1 … >]
|
Интересные строки здесь — 3 и 5. Мы могли бы сделать o.person_id = p.id
, но из-за наших дополнений к модельным классам o.person = p
— более короткий способ сделать то же самое. Затем строка 5: это еще один из этих добавленных методов: он возвращает массив всех заказов, которые есть у нашего сотрудника. Удобно, нет?
Это хорошее резюме того, что вы можете делать с ассоциациями Active Record; есть тонна больше, и это может стать довольно сложным. Проверьте документацию Ассоциаций для всего хорошего.
Выбор записей
Все это время мы создавали классы Active Record или создавали записи моделей. Однако большая часть работы с классом Active Record возвращает эти записи обратно. Как и следовало ожидать, существует около десятка методов, которые мы можем использовать.
Первый и самый простой — это методы, которые возвращают все записи:
1
|
Person.all
|
Метод all
возвращает массив всех записей.
Также есть команда find
, которая принимает id
в качестве параметра и возвращает запись с этим идентификатором; он также может взять массив id
и вернуть соответствующие записи:
1
2
3
4
|
Person.find 2
#=> #<Person id: 2 … >
Person.find [2,4,6]
#=> [#<Person id: 2 … >, #<Person id: 4 …>, #<Person id: 6 …> ]
|
Если вам просто нужна первая или последняя запись в коллекции, для этого есть специальные методы:
1
2
|
Person.first
Person.last
|
Одна из самых крутых возможностей Active Record — это пользовательские методы поиска; внизу это просто использование method_missing
, но сверху это выглядит как чистая магия. Вот как это работает: используйте имя метода find_by_<property>
и передайте значение этого свойства в качестве параметра. Например:
1
2
|
Person.find_by_first_name «John»
#=> #<Person id: 1, first_name: «John» .
|
Вы можете даже связать свойства; эта команда вернет ту же запись:
1
|
Person.find_by_first_name_and_last_name «John», «Doe»
|
Если вы посмотрите на запросы SQL для этих двух последних методов, то увидите, что мы возвращаем только первый результат ( LIMIT 1
). Чтобы найти все подходящие записи, используйте вместо этого префикс find_all_by
. Так:
1
2
|
Person.find_all_by_first_name «John»
Person.find_all_by_first_name_and_last_name «John», «Doe»
|
Это становится еще лучше: вы можете использовать префикс find_or_create_by
для создания записи, если не найдено ни одной соответствующей записи:
1
|
p = Person.find_or_create_by_first_name_and_last_name_and_age «Bob», «Smith», 45
|
Да, это на самом деле работает. Однако следует понимать, что если запись не найдена, это все равно что запустить Person.create
, который выполняет проверки. Так, например, поскольку требуются last_name
и age
, выполнение этой команды приведет к появлению несохраненных записей:
1
|
Person.find_or_create_by_first_name «Lindsey»
|
Если вы не хотите, чтобы новая запись была сохранена сразу, используйте префикс find_or_initialize_by
.
1
|
Person.find_or_initialize_by_first_name «Lindsey»
|
Есть несколько других методов, которые могут оказаться полезными при выборе записей. Действительно полезным является тот, where
берется предложение WHERE
из оператора SQL.
1
|
Person.where(«first_name like ‘A%'»)
|
Если вы берете значения от пользователя для использования where
, where
вы не должны интерполировать их, опасаясь инъекций SQL. Вместо них следует использовать вопросительные знаки, а затем передать значения в качестве других параметров:
1
|
Person.where(«first_name like ?», params[:name_starts_with])
|
, , , или что-то подобное.
Все эти методы, которые мы рассмотрели до сих пор, возвращают все поля возвращенных записей. Вы можете использовать метод select
перед любым из них, чтобы возвращать только экземпляры модели с несколькими выбранными свойствами:
1
2
|
Person.select(:first_name).first
Person.select(«last_name, age»).find_by_first_name(«Andrew»)
|
Другие общие действия оператора SQL включают ограничение и смещение; отличным вариантом использования для этого являются результаты подкачки. Методы limit
и offset
принимают один числовой параметр каждый. Если вы используете их в одиночку, они работают на всю коллекцию; например, это возвращает пять записей, пропуская первые две:
1
|
Person.offset(2).limit(5)
|
Но вы можете выбрать записи для ограничения и смещения с помощью одной из других функций:
1
|
Person.select(:id).limit(2).offset(2).find_all_by_first_name «Andrew»
|
Есть несколько других методов запросов, но мы рассмотрели те, которые вы собираетесь использовать в 90% случаев.
Если вы делаете сложные запросы, подобные этой, было бы неплохо создать собственный метод запроса в ваших классах моделей. Допустим, мы позволяем людям искать других пользователей по их фамилии, и мы отображаем результаты по 10 пользователей на страницу. Запрос может выглядеть примерно так:
1
|
Person.offset(0).limit(10).find_by_last_name(params[:search_term])
|
Помимо того, что это довольно долго для контроллера, это смещение должно меняться для каждой страницы; 0
работает только для первой страницы. Итак, мы пишем метод в нашем классе Person
:
1
2
3
|
def self.search(term, page = 1, per_page = 10)
Person.offset( per_page * (page — 1)).limit(per_page).find_all_by_last_name term
end
|
Это возвращает набор, который мы хотим, и мы можем выбрать, какую страницу и сколько результатов на странице мы бы хотели (или оставить их с их разумными значениями по умолчанию. И даже лучше, это хороший аккуратный метод, который мы можем вызвать из нашего контроллера следующим образом :
1
2
|
Person.search «Smith» # page 1
Person.search «Smith», 2 # page 2
|
Подробнее о запросах см. Документацию запросов Active Record .
Вывод
Если вы только начинаете изучать Rails, вы только что узнали практически все, что вам нужно знать об Active Record. Конечно, как и любая другая часть Rails, Active Record глубокая и насыщенная; Есть много вещей, которые я не упомянул в этом уроке. Подробнее об этом смотрите в Руководстве по Rails для моделей . Спасибо за прочтение!