# | name | last name | age | create_date | updated_at |
1 | John | Doe | 31 | 29.07.2008 | 29.07.2008 |
2 | Sergey | Saenko | 23 | 29.07.2008 | 29.07.2008 |
3 | Ivan | Petrenko | 25 | 29.07.2008 | 29.07.2008 |
Как же работает с SQL используя ActiveRecord?
Для того чтобы делать выборки из базы, для каждой модели существует метод Find. Посмотрим на простом примере как же он работает:
User.find(1) - результатом такого запроса будет первая запись нашей таблицы, которая соответствует пользователю John Doe, результатом выполнения запроса будет обьект класа User.
Таким образом, если метод find() принимает в качестве параметра число, то он будет искать запись, ІD которой будет соответствовать параметру.
User.find(:all) - вернет коллекцию єкземпляров класса User. Согласно переданому параметру - выберет все записи из таблицы.
User.find(:first), и по аналогии User.find(:last) - эти два запроса соответственно вернут первого и последнего зарегистрированного пользователя в системе.
При генерации любой модели, независимо от полей таблицы заданных в миграции - в автоматическом режиме создаются 2 дополнительных поля:
create_date и updated_at которые имеют тип дата/время. Оба поле заполняется автоматически при создании записи(дата создания и дата обновления сначала совпадают), но второе поле автоматически изменяется при любой модификации записи.
Так к чему же я это все писал - при любой выборке коллекции записей, данные будут отсортированы как-раз по полю create_date (если порядок сортировки не задан в явном виде). Таким образом я точно знаю что User.find(:first) вернет первый созданный обьект, а User.find(:last) соответствует последнему созданному экземпляру User.
Немного отвлекусь от темы. Рельсы сделаны очень интиресным образом, сейчас немного объясню свое понимание почему же фреймворк назвали именно Рельсы. Все что можно было задать по-умолчанию - разработчики фрейворка уже описали. Другими словами частичное поведение всех методов и классов при их генерации уже заданы, и менять программисту нужно только то что ему надо. Таким образом у нас как-бы есть уже "сырые заготовки", которые осталось только немного подправить и настроить. Создается впечатление, что все делается как-бы по накатанному пути - "как по рельсам". На самом деле все не так, Руби очень гибкий язык программирования, который позволяет реализовать в принципе любой алгоритм. Рельсы писались на Руби, то понятно что это очень быстрый в разработке и довольно гибкий - учитывая язык на котром он написан - инструмент разработки. Но повторяю - это только мое субъективное мнение.
Для того чтобы задать параметры выборки используется метод :conditions, например:
User.find(:all, :conditions=>"age=23") - выберет второго пользователя.
Чтобы передавать в :conditions параметры, можно использовать следующие способы:
name = "Sergey"
1. User.find(:all,:conditions=>["name=:name",{:name=>name}])
2. User.find(:all,:conditions=>["name= ?",name])
3. User.find(:all,:conditions=>"name=#{name}")
Рельса в любом из 3 случаев предварительно формирует для БД запрос, а потом его отсылает. Тоесть неверно говорить что что параметры на сервере в 1 и 2 передаются отдельно, а ядро запроса кешируется. В любом случае на сервер идет готовый запрос, проверял лично. По скорости работы выигрывает на сотые доли секунды 3 вариант, но его целиесобразно использовать только если мы не вставляем в параметры пользовательские данные. Для того чтобы предотвратить сюл-иньекции используйте вариант 1 или 2.
И как завершение я расскажу разницу вариантов 1 и 2. В первом случае, мы передаем именованые параметры, тоесть, в случае если надо чтобы 1 параметр встречался в запросе боьше одного раза, во 2 варианте придется через запятую 2 раза его дублировать:
User.find(:all,:conditions=>["start_date= ? and end_date = ?",current,current])
а в 1 варианте можно сделать так:
User.find(:all,:conditions=>["start_date= :current_date and end_date = :current_date",{:current_date=>current}])
таким образом удается избавится от избыточности параметров
Сonditions- очень похожи на С-функцию sprintf, так что сложности с пониманием быть не должно. А само тело условия формируется аналогично постороения условия запроса через WHERE.
Спасибо огромное! Вы так понятно объясняете и отвечаете как раз на те вопросы, которые хочется задать.
ОтветитьУдалитьНе могли бы Вы добавить описание, как выбрать связанные данные из двух таблиц?
Что-то вроде "SELECT tab1.long_eng, tab2.translation FROM tab1, tab2 WHERE tab1.l_eng_word LIKE tab2.eng_word"
Освободится немного времени и обязательно отвечу! Думаю в понедльник-вторник.
ОтветитьУдалить