Статьи

10 лучших практик Ruby on Rails

Если вы новичок в Ruby on Rails, одним из самых сложных аспектов является знание того, какой предпочтительный способ выполнения данной задачи. В то время как многие методы и библиотеки пришли и ушли как предпочтительный способ сделать что-то для сообщества, есть некоторые лучшие практики, которые остаются и могут привести к написанию самого чистого, самого безопасного и поддерживаемого кода Rails из возможных.

Здесь перечислены 10 самых популярных и полезных рекомендаций, которые вы можете использовать в качестве разработчика Ruby.

Толстая Модель, Тощий Контроллер

Возможно, один из самых важных способов написания ясного и лаконичного кода на Ruby on Rails, девиз «Толстая модель, Skinny Controller» относится к тому, как части M и C MVC идеально работают вместе. А именно, любая логика, не связанная с ответом, должна входить в модель, в идеале — в хороший, проверяемый метод. Между тем, «тонкий» контроллер — это просто приятный интерфейс между представлением и моделью.

На практике это может потребовать ряда различных типов рефакторинга, но все сводится к одной идее: перемещая любую логику, которая не относится к ответу (например, устанавливая флэш-сообщение или выбирая, перенаправлять или визуализировать представление) для модели (вместо контроллера), вы не только способствовали повторному использованию, где это возможно, но и сделали возможным тестирование вашего кода вне контекста запроса.

Давайте посмотрим на простой пример. Скажем, у вас есть такой код:

def index @published_posts = Post.all :conditions => {['published_at <= ?', Time.now]} @unpublished_posts = Post.all :conditions => {['published_at IS NULL OR published_at > ?', Time.now]} end 

Вы можете изменить это на это:

 def index @published_posts = Post.all_published @unpublished_posts = Post.all_unpublished end 

Затем вы можете переместить логику в вашу модель поста, где она может выглядеть так:

 def self.all_published all :conditions => {['published_at <= ?', Time.now]} end def self.all_unpublished all :conditions => {['published_at IS NULL OR published_at > ?', Time.now]} end 

С помощью методов Post.all_published и Post.all_unpublished мы не только упростили тестирование нашего кода, но и сделали возможным повторное использование этого же набора условий в другом месте. Но, как мы скоро увидим, даже это все еще не идеально.

Многоразовые Области и Отношения

В приведенном выше примере мы все еще не были на оптимальном уровне. Например, что если мы хотим получить один опубликованный пост? Нам пришлось бы продублировать условия в другом методе, который просто приводит к все большему количеству ненужного кода.

К счастью, Rails предоставляет лучший способ — области видимости (в более старых версиях Rails их называли именованными областями ). Проще говоря, область действия — это набор ограничений на взаимодействия с базой данных (таких как условие, лимит или смещение), которые можно объединять и использовать повторно. В результате я могу вызвать MyModel.my_scope.another_scope или MyModel.my_scope.first или MyModel.my_scope.all .

Итак, снова взяв наш предыдущий пример, мы можем переписать его следующим образом в Rails 3:

 scope :published, lambda { where('published_at < = ?', Time.now) } scope :unpublished, lambda { where('published_at > ?', Time.now) } 

И в Rails 2:

 named_scope :published, lambda { {:conditions => ['published_at < = ?', Time.now]} } named_scope :unpublished, lambda { {:conditions => ['published_at > ?', Time.now]} } 

Это позволит нам использовать Post.published.all и Post.unpublished.all где это необходимо.

Более того, в Rails 3 Rails теперь поддерживает отношения — по сути, произвольные области видимости, которые можно использовать где угодно. Например, Post.where(:title => 'Hello World').first Post.first :conditions => {:title => 'Hello World'} вместо Post.first :conditions => {:title => 'Hello World'} , что означает, что теперь вы получаете мощные функции, такие как создание цепочек для произвольной базы данных. звонки.

Это приводит к лучшему построению кода и большему количеству повторяющихся запросов — вы начинаете думать о том, чего может достичь область или комбинация областей, иными словами, общая картина, а не о том, каков ваш единственный запрос. В качестве бонуса гораздо удобнее составлять очень сложные запросы, такие как поиск, просто добавляя необходимые связи и области.

Упакуйте свой код в Gems и плагины

Если вы использовали Ruby on Rails приличное количество, вы, скорее всего, заметили множество рубинов, доступных для разработчиков Rails. Если есть относительно общая проблема, вполне вероятно, что другой разработчик уже решил ее.

Итак, когда вы пишете код, который вы считаете достаточно общим — что обычно означает, что вы написали его более одного раза в другом приложении, остановитесь и подумайте о том, как вы можете извлечь его в плагин или гем, подходящий для более широкого диапазона целей. , Это не только окупается в следующий раз, когда вам понадобится упомянутая функциональность, но также заставляет вас остановиться и оценить свой подход к проблеме — чаще всего я обнаружил, что извлечение кода из приложения приводит к упрощению дизайна. Вы также не должны забывать, что, как разработчик, выпуск открытого исходного кода может окупиться другими способами.

Когда речь заходит об использовании этого кода в следующий раз, в качестве дополнительного бонуса он, как правило, уже протестирован и хорошо изучен, что в результате приводит к получению лучшего кода из нескольких этапов рефакторинга.

В том же духе потратьте некоторое время на изучение драгоценных камней с открытым исходным кодом, которые уже решают ваши проблемы. Если вы не уверены, с чего начать, поиск в GitHub обычно является хорошей отправной точкой, а Ruby Toolbox содержит список самых популярных плагинов в сообществе.

Используйте встроенные методы печати Ruby Duck

Как язык, Ruby использует несколько соглашений, которые могут упростить разработку. Например, реализация to_s экземпляра to_s для объекта даст вам стандартный способ получения строкового представления вашего объекта.

to_s эти стандартные преобразования типов — в дополнение к to_s , есть также to_i для целых чисел и to_a для массивов — вы делаете свой код Ruby более кратким. В качестве примера рассмотрим следующую интерполяцию строк:

 "Hello there, #{user.name}" 

Если вы to_s псевдоним атрибута to_s , вы можете просто написать

 "Hello there, #{user}" 

Другие места в Ruby, которые используют to_s (и, для других ситуаций, to_i и т.п.), автоматически воспользуются этим строковым представлением вашего объекта.

Наряду с этим, вы также можете реализовать модуль Enumerable для любого из ваших классов, который вы хотите предоставить с полезными функциями итерации. Все, что вам нужно написать в своем классе, это методы each и <=> . Эти два простых дополнения дают вам полную кучу дополнительных функциональных возможностей бесплатно: такие методы, как map , inject , sort , max , min и ряд других.

Управление доступом к атрибутам

По умолчанию при использовании массового присвоения в Rails, то есть кода, аналогичного User.new(params[:user]) и @user.update_attributes params[:user] Rails назначит каждый атрибут без какой-либо проверки. Ваши проверки предотвращают неверные данные, но они, например, не мешают вам перезаписать атрибут, который вы не хотите изменять.

Чтобы решить эту проблему, ActiveRecord использует два метода — attr_protected и attr_accessibile . Используя attr_protected , вы объявляете черный список переменных, которые вы не хотите назначать (например, attr_protected :admin, :password_hash ). Используя attr_accessible, который обычно предпочтительнее, вы объявляете те, которые хотите назначить (например, attr_accessible :login, :email, :password, :password_confirmation ).

Делая это, вы предотвращаете любое массовое присвоение, которое может произойти через формы вашего приложения — просто потому, что у вас нет поля для данного атрибута, не означает, что хакер не может добавить его в запрос. Таким образом, вы либо вынуждены вручную устанавливать определенные значения атрибута, либо, что более полезно, предоставлять защищенный метод для использования, когда вы хотите установить значение.

С точки зрения безопасности использование attr_accessible и attr_protected заставляет задуматься о том, что должно быть редактируемым и как защитить способы установки атрибутов вашего класса.

Используйте не поддерживаемые базой данных модели

Хотя модели в Rails в основном основаны на ActiveRecord::Base или каком-либо другом типе объектного сопоставителя для базы данных, важно помнить, что в MVC M не ограничивается моделями, поддерживаемыми базой данных.

Использование моделей без поддержки базы данных может помочь организовать логику, которая в противном случае могла бы стать грязной. Например, есть библиотеки, которые предоставляют ActiveRecord подобный интерфейс для электронных писем в контактной форме .

Используя ActiveModel (доступно в Rails 3 и выше), можно взять произвольные объекты, которые инкапсулируют набор общих действий, и использовать их в качестве ваших моделей. Добавление виртуальных моделей также упрощает использование конструкции контроллера RESTful, поскольку вы можете представлять данные, отличные от записей базы данных, в качестве ресурсов. В качестве основного примера, несколько популярных библиотек аутентификации в Rails теперь представляют текущий сеанс аутентификации пользователя в качестве модели, и я лично реализовал сброс пароля в качестве модели.

Когда придет время взаимодействовать с этими моделями в коде вашего контроллера, ваш код будет намного чище, так как вы сможете использовать тот же подход, что и в моделях на основе базы данных.

Виртуальные атрибуты

Если вы обнаружите, что манипулируете данными, прежде чем передавать их в модель (например, конвертируете тип объекта), скорее всего, вы начали структурировать свой код, чтобы использовать преимущества виртуальных атрибутов .

Виртуальные атрибуты — очень простая идея, по сути, все, что вы делаете, это определяете свои собственные методы получения и установки.

Допустим, вы использовали следующий код для установки имени пользователя:

 @user = User.new(params[:user]) @user.first_name, @user.last_name = params[:user][:full_name].split(" ", 2) 

Вы можете удалить вторую строку и вместо этого добавить следующее в свою модель User:

 def full_name=(value) self.first_name, self.last_name = value.to_s.split(" ", 2) end 

Каждый раз, когда вы устанавливаете атрибут full_name , ваша модель теперь автоматически устанавливает атрибуты first_name и last_name для вас, даже если full_name не существует в базе данных. Точно так же вы, как правило, захотите определить метод получения, full_name , который возвращает "#{first_name} #{last_name}" .

Используя виртуальные атрибуты, вы можете использовать альтернативные представления данных в формах с относительно небольшими усилиями. Также намного проще тестировать логику изолированно, что всегда хорошо.

Использовать переводы

Начиная с Rails 2.2, сам фреймворк поставляется с мощной поддержкой интернационализации (или i18n ) из коробки. Все, что вам нужно сделать, это сохранить файл переводов YAML и использовать I18n.t / t в своем коде, где есть данные, показанные пользователю. По сути, инфраструктура Rails i18n позволяет легко объявлять отображение абстрактного контекста в строку.

С точки зрения разработчика, использование I18n полезно не только для развертывания вашего приложения в большем количестве языков. Когда приходит время переименовывать что-то в вашем интерфейсе, наличие единого места для поиска рассматриваемой строки, чтобы заменить ее во всем приложении, гораздо быстрее, чем чистить код в каждом случае.

Если вы хотите начать работу с фреймворком Rails I18n, существует очень подробное руководство, которое свободно доступно сообществу.

В заключение

Существуют буквально сотни практик или методов кодирования, которые могут упростить вашу жизнь как разработчика Ruby on Rails, но я попытался выделить десять, которые широко применимы практически ко всем проектам, и которые часто игнорируются. Вы уже придерживаетесь этих методов? Вы начнете? У вас есть другие, которые вы бы добавили? Дай мне знать в комментариях.