Статьи

Активная запись: Мост базы данных Rails

В прошлом для создания веб-приложения требовались навыки написания кода на языке бизнес-логики и языке базы данных. Однако в последнее время серверные инфраструктуры склоняются к использованию объектно-реляционного сопоставления (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. Это та часть, с которой вы на самом деле будете взаимодействовать со своими контроллерами 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. В текущих версиях 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 .


Обратные вызовы — еще одна интересная часть 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 для моделей . Спасибо за прочтение!