Заметка не новая, но я уверен, что и сейчас не все знают всё нижеперечисленное (Здесь и далее курсив переводчика).
Когда я смотрю на свой, да и на чужой, код на рельсах, я часто вижу нереализованные возможности для применения определённых рельсовых техник. Я бы хотел перечислить некоторые приёмы и советы для повышения эффективности приложения и кода, как памятку для себя и для вас.
Замер скорости в контроллерах — это очень просто. Используйте метод benchmark в любой модели.
Ваш код, конечно, будет получше ;-) Обычные SQL логи не будут писаться внутри метода benchmark, только результаты.
acts_as_nested_set — почти все (хо-хо) хорошо знакомы с acts_as_tree, но незаметно в рельсах появилось acts_as_nested_set. Это похоже на acts_as_tree, но с удобствами: вы можете выбрать всех детей (и их наследников) одного узла одним запростом. Имеется список методов.
Простые коллекции через to_proc — надоело писать
Превращение массивов в предложения — если вам в показе (view) надо вывести список имён, вы берёте массив типа
Отправка файла пользователю — обычно статические файлы передаются по прямому УРЛу в обход рельсового приложения. Тем не менее в ряде ситуаций может быть полезно спрятать расположение файла, особенно если вы посылаете что-либо ценное, наподобии е-книги. Может также требоваться ограничить посылку файлов только залогиненным пользователям. Проблему решает
Выборка элементов страницы через RJS — поменять элемент в RJS нетрудно, но что если мы не знаем, какой именно элемент надо менять, и хотели бы адресоваться через CSS-запрос? Это возможно с методом select. Например,
Проверка существования — при выполнении Model.find(id) мы получим исключение, если элемента «id» не нашлось. Чтобы это избежать, сперва выполняем Model.exists?(id), чтобы узнать, есть ли такой.
Числовые хелперы для частых задач — они нечасто используются, но тем не менее весьма полезны:
Простое тестирование роутинга — test_routing — хелпер, который подменяет умолчательный «routes» в routes.rb для опытов. Например:
Здесь подробнее.
Много интересного о запросе —
Дальнейшее повышение производительности — по умолчанию рельсы записывают сессии на локальную файловую систему. Многие меняют это на ActiveRecordStore для записи сессий в базу. Ещё более быстрая альтернатива будет Memcached, но его не так лекго установить (и не получится, если сервера чужие, и т.д.). И тем не менее можно сделать быстрее, чем ActiveRecordStore, через использование SQLSessionStore Стефана Кейса (Stefan Kaes). Плагин обходит недостатки ActiveRecordStore через свою SQL технику сохранения сессий.
Кеширование статического контента при старте — если у вас есть данные, которые не меняются от рестарта к рестарту, закешируйте их. Например, это мог бы быть YAML или XML файл в /config-e с настройками приложения, и его можно загружать в константу в environment.rb, ускоряя и упрощая доступ.
Проверка валидности (X)HTML-а — не для всех, но если ваш вывод валиден, то есть шансы, что ваши показы (view) рендерятся правильно. Скот Реймонд (Scott Raymond) разработал хелпер assert_valid_markup, который можно использовать для функционального тестирования.
Более опрятное тестирование HTML-вывода — объединим парсер Hpricot от вая (why) со специальным тестовым расширение, и получим мощные тесты наподобие
Запуск длинных процессов отдельно в фоне — есть небольшой фреймворк
Красивые иды в УРЛах — заменим
Выделение кусков функциональности в энжины — все слышали про плагины, но прискорбно мало кто используюет энжины (engines)! Энжины это плагины на стероидах (или на барбитуратах). У них могут быть свои модели, контроллеры и показы, и они могут интегрироваться с любым приложением. Это позволяет выделять общие куски функциональности (логины, управление пользователями, контент-менеджмент и т.п.) в отдельные «движки», которые можно включать в разные проекты за считанные минуты. Скажем нет писанию дурацких логинов! Энжины это круто, но должны быть ещё гораздо круче.
Вычисления — желаете вычислить максимум, минимум, среднее, сумму для данных в таблице? Это возможно, с Calcuations из
Вывод данных в XML или YAML — не только, чтобы создать .rxml шаблон Builder-a для вывода в XML. У
Когда я смотрю на свой, да и на чужой, код на рельсах, я часто вижу нереализованные возможности для применения определённых рельсовых техник. Я бы хотел перечислить некоторые приёмы и советы для повышения эффективности приложения и кода, как памятку для себя и для вас.
Замер скорости в контроллерах — это очень просто. Используйте метод benchmark в любой модели.
User.benchmark("adding and deleting 1000 users") do 1000.times do User.create(:name => 'something') x = User.find_by_name('something') x.destroy end end
Ваш код, конечно, будет получше ;-) Обычные SQL логи не будут писаться внутри метода benchmark, только результаты.
acts_as_nested_set — почти все (хо-хо) хорошо знакомы с acts_as_tree, но незаметно в рельсах появилось acts_as_nested_set. Это похоже на acts_as_tree, но с удобствами: вы можете выбрать всех детей (и их наследников) одного узла одним запростом. Имеется список методов.
Простые коллекции через to_proc — надоело писать
post.collect { |p| p.title }
или post.select { |p| p.activated? }.collect{ |p| p.title}
? С помощью небольшого хака переводим символы в процедуры. Можно писать post.collect(&:title)
или post.select(&:activated?).collect(&:title)
! Здесь об этом куда больше.Превращение массивов в предложения — если вам в показе (view) надо вывести список имён, вы берёте массив типа
['Peter', 'Fred', 'Chris']
, соединяете запятыми и добавляете «and» перед последним, что могло бы поднадоесть. Метод to_sentence
спешит на помощь: names.to_sentence
вернёт "Peter, Fred, and Chris"
. (Да, это не портабельно и англоцентрично. В примечаниях к оригинальной статье об этом больше.)Отправка файла пользователю — обычно статические файлы передаются по прямому УРЛу в обход рельсового приложения. Тем не менее в ряде ситуаций может быть полезно спрятать расположение файла, особенно если вы посылаете что-либо ценное, наподобии е-книги. Может также требоваться ограничить посылку файлов только залогиненным пользователям. Проблему решает
send_file
. Файлы передаются по 4096 байтов, так что даже большие файлы систему не затормозят.Выборка элементов страницы через RJS — поменять элемент в RJS нетрудно, но что если мы не знаем, какой именно элемент надо менять, и хотели бы адресоваться через CSS-запрос? Это возможно с методом select. Например,
page.select('#items li').each { |item| item.hide }
. Мощная штука!Проверка существования — при выполнении Model.find(id) мы получим исключение, если элемента «id» не нашлось. Чтобы это избежать, сперва выполняем Model.exists?(id), чтобы узнать, есть ли такой.
Числовые хелперы для частых задач — они нечасто используются, но тем не менее весьма полезны:
number_to_currency(1234567.948) # => $1,234,567.95
или human_size(1234567890) # => 1.1GB
или number_with_delimiter(999999999) # => 999,999,999
. Есть и другие. (То же замечание относительно локализации.)Простое тестирование роутинга — test_routing — хелпер, который подменяет умолчательный «routes» в routes.rb для опытов. Например:
with_routing do |set| set.draw { set.connect ':controller/:id/:action' } assert_equal( ['/content/10/show', {}], set.generate(:controller => 'content', :id => 10, :action => 'show') ) end
Здесь подробнее.
Много интересного о запросе —
request.post?
и request.xhr?
— популярные способы посмотреть на POST- и аякс-запросы, но есть и другие, не столь известные. Например, request.subdomains
вернёт массив поддоменов, который можно использовать при авторизации, request.request_uri
даст полный локальный URI, request.host
это полное имя хоста, request.method
вернёт метод в нижнем регистре, и request.ssl?
определит, SSL ли это.Дальнейшее повышение производительности — по умолчанию рельсы записывают сессии на локальную файловую систему. Многие меняют это на ActiveRecordStore для записи сессий в базу. Ещё более быстрая альтернатива будет Memcached, но его не так лекго установить (и не получится, если сервера чужие, и т.д.). И тем не менее можно сделать быстрее, чем ActiveRecordStore, через использование SQLSessionStore Стефана Кейса (Stefan Kaes). Плагин обходит недостатки ActiveRecordStore через свою SQL технику сохранения сессий.
Кеширование статического контента при старте — если у вас есть данные, которые не меняются от рестарта к рестарту, закешируйте их. Например, это мог бы быть YAML или XML файл в /config-e с настройками приложения, и его можно загружать в константу в environment.rb, ускоряя и упрощая доступ.
Проверка валидности (X)HTML-а — не для всех, но если ваш вывод валиден, то есть шансы, что ваши показы (view) рендерятся правильно. Скот Реймонд (Scott Raymond) разработал хелпер assert_valid_markup, который можно использовать для функционального тестирования.
Более опрятное тестирование HTML-вывода — объединим парсер Hpricot от вая (why) со специальным тестовым расширение, и получим мощные тесты наподобие
assert_equal "My title", tag('title')
или assert element('body').should_contain('something')
. Это идеально подходит для тестирования пользовательских шаблонов. Так или иначе, уж лучше, чем assert_tag
!Запуск длинных процессов отдельно в фоне — есть небольшой фреймворк
BackgrounDRb
от Эзры Зигмунтовича (Ezra Zygmuntovich), который запускается в виде демона и принимает задачи от рельсового приложения, и выполняет их независимо. Мощная вещь, помогает в рассылке писем, получении УРЛов, и прочего, что может затормозить время выполнения запроса основного приложения. Демо-таск увеличивает переменную на 1, после чего делает sleep
на 1 секунду. Далее делаем рельсовый метод, который опрашивает эту переменную, и чувствуем разницу. Здесь больше.Красивые иды в УРЛах — заменим
to_param
в вашей модели и вернём что-нибудь вроде "#{id}-#{title.gsub(/[^a-z0-9]+/i, '-')}"
, для УРЛа вида yoursite.com/posts/show/123-post-title-goes-here...
. Куда приятнее для пользователя, и не надо ничего менять в Post.find(params[:id])
, так как нецифровые символы будут выкинуты автомагически. Полное объяснение тут. (ссылка битая, похоже)Выделение кусков функциональности в энжины — все слышали про плагины, но прискорбно мало кто используюет энжины (engines)! Энжины это плагины на стероидах (или на барбитуратах). У них могут быть свои модели, контроллеры и показы, и они могут интегрироваться с любым приложением. Это позволяет выделять общие куски функциональности (логины, управление пользователями, контент-менеджмент и т.п.) в отдельные «движки», которые можно включать в разные проекты за считанные минуты. Скажем нет писанию дурацких логинов! Энжины это круто, но должны быть ещё гораздо круче.
Вычисления — желаете вычислить максимум, минимум, среднее, сумму для данных в таблице? Это возможно, с Calcuations из
ActiveRecord
. Person.average('age'), Person.maximum(:age, :group => 'last_name'), Order.sum('total')
: всё это теперь воплощается. Большинство из этого можно настроить дополнительными опциями, почитайте, если этого ещё нет у вас в коде.Вывод данных в XML или YAML — не только, чтобы создать .rxml шаблон Builder-a для вывода в XML. У
ActiveRecord
есть метод to_xml
, выводящий результат в XML. Работает как с простыми объектами, так и с целыми таблицами: User.find(:all).to_xml
. Инклуды также поддерживаются: Post.find(:all, :include => [:comments]).to_xml
. То же самое в YAML, с помощью to_yaml
.