Статья из моих архивов
В этом посте хочу рассказать о некоторых небольших трюках и неочевидных вещах, которые, я надеюсь, помогут вам увеличить продуктивность разработки и качество приложений.
Rails Console
Наверное, все разработчики на Rails используют консоль, или хотя бы слышали о ней. Запускается она из папки проекта:
./script/console
На самом деле, консоль Rails — не что иное, как простой irb (Interactive Ruby — интерактивный интерпретатор Руби), в который подгружено окружение нашего проекта. В основном консоль используется для отладки приложений.
Режим “песочница”
Если нам нужно проверить что-то на рабочей базе, либо при наших дейсвиях возможно сильно испортить существующие данные, нам нужна возможность отката всех наших действий после выхода из консоли. И она у нас есть! Это и называется режимом “песочница” и включается он указанием параметра —sandbox при запуске консоли:
./script/console --sandbox
Читабельный вывод атрибутов модели
Как известно, для вывода на консоль содержимого какого-либо объекта в irb используется метод inspect. При выводе коллекции моделей это не сильно помогает, так как все атрибуты начинают рябить в глазах. Можно упростить себе жизнь, используя метод “y”. Запись
y my_model
Эквивалентна
puts my_
model.to
_yaml
То есть мы получаем модель, сериализованную в YAML, что заметно улучшает читабельность.
Если же вас не устраивает и это, то нично не мешает переопределить метод inspect для ActiveRecord. Сделать это можно в файлике ~/.irbrc (если его нет — нужно создать). Это файл выполняется каждый раз при запуске irb и содержит обычный руби-код. То есть нам нужно поместить туда что-то вроде
class ActiveRecord::Base def inspect # тут ваш код end end
Лог в консоль
Иногда нужно знать какие запросы к базе данных делаются при вызове того или иного метода (особенно полезно при обучении и отладке кода). Как известно, выводом всяческой информации заведует экземпляр класса Logger, находящийся в классе ActiveRecord::Base. Следовательно,
ActiveRecord::Base.logger =
Logger.new
(STDOUT)
даёт нам желаемый результат. Можем при необходимости также положить эту строчку в ~/.irbrc
Mass assignment
Очень удобно где-то в контроллере далать что-то подобное:
@my_model = MyModel.create params[:my_model]
Собственно, это и называется mass assignment — “множественное присвоение”. Всё хорошо. Но рассмотрим такую ситуацию: у нас в модели есть поля, которые могут устанавливаться только в определённых ситуациях, например, есть модель Post, у которой могут быть комментарии и рейтинг (помимо, естественно, тела и заголовка). И есть контроллер PostsController, у которого в экшене new написано что-то вроде
@post = Post.create params[:post]
Тогда кто-то с нехорошими намерениями может сделать ручками запрос на нашу страничку и спокойно поставить любой рейтинг посту. Более того, он сможет добавлять комментарии к посту. Как же нам этого избежать? Неужели, придётся в каждом месте писать что-то типа
@my_model =
MyModel.new
@my_model.attr1 = params[:my_model][:attr1] @my_model.attr2 = params[:my_model][:attr2] # и ещё 25 параметров
К счастью, нет. В ActiveRecord есть два замечательных метода: attr_protected и attr_accessible. Первый защищает переданные ему атрибуты модели от mass assignment, а второй, наоборот, принимает список атрибутов, которые могут быть присвоены через mass assignment.
Проще говоря, если мы пишем в модели
attr_protected :attr1, :attr2
То при выполнении строки
@my_model = MyModel.create { :attr1 => 1, :attr2 => 2, :attr3 => 3 }
Значения атрибутов attr1 и attr2 будут игнорированы. А если напишем так:
attr_accessible :attr3
То присвоить через mass_assignment можно будет только attr3.
ActiveRecord#find
В большинстве случаев ограничиваюсь
MyModel.find :all, :conditions => { :filed1 => val1 }
или
MyModel.find :all, :conditions => ['field1 = ? or field1 = ?', val1, val2]
Но недавно открыл для себя такую интересную возможность: к примеру, нам нужно сгруппировать модели по какому-то полю. Делается это примерно так:
MyModel.find :all, :group => 'group_field'
А как быть, если нам нужно не только группировать, но и знать, к примеру, количество сгруппированных записей? Оказыватся, при выполнении кода:
MyModel.find :all, :group => 'group_field', :select => '*, count(*) as group_size'
group_size отлично замаппится в атрибуты модели. То есть, мы сможем спокойно писать:
MyModel.find(:all, :group => 'group_field', :select => '*, count(*) as group_size').each do |my_model| my_
model.group
_size # => вернёт вам размер группы end