Ролевые модели важны.
-- Офицер Алекс Мёрфи / Робот-полицейский
Целью этого руководства является распространение набора проверенных практик и стилистических рекомендаций при разработки приложений с помощью Ruby on Rails (для версий 3 и 4). Это руководство дополняет уже существующий сборник: Руби: руководство по стилю оформления.
Некоторые из приведенных здесь рекомендаций будут применимы только к Rails 4.0+.
Вы можете создать копию этого руководства в форматах PDF или HTML при помощи Pandoc.
Переводы данного руководства доступны на следующих языках:
- английский (исходная версия)
- китайский традиционный
- китайский упрощенный
- корейский
- немецкий
- русский (данный документ)
- турецкий
- японский
Настоящее руководство по стилю рекомендует лучшие практики оформления, благодаря которым обычные разработчики на Rails смогут писать код, который с легкостью будут поддерживать другие обычные программисты. Руководство по оформлению, которое отражает повседневные реалии, будет применяться постоянно, а руководство, стремящееся к идеалу, который не принимается рядовыми специалистами, подвергается риску вообще быть забытым. При этом абсолютно не важно, насколько хорошим оно является.
Данное руководство разделено на несколько частей, состоящий из связанных по смыслу правил. В каждом случае мы попытались обосновать появление этих правил (объяснение опущено в ситуациях, когда мы посчитали его очевидным).
Все эти правила не появились из пустоты, они по большей части основываются на нашем собственном обширном профессиональном опыте в разработке ПО, отзывах и предложениях других членов сообщества разработчиков на Rails и различных общепризнанных источниках по созданию Rails-приложений.
- Конфигурация
- Маршрутизация
- Контроллеры
- Модели
- Миграции
- Представления
- Интернационализация
- Ресурсы
- Почтовые модули
- Active Support Core Extensions
- Время
- Bundler
- Управление процессами
-
Код для инициализации приложения помещайте в директорию
config/initializers/
. Код в этой директории выполняется при запуске приложения. [ссылка] -
Для каждого гема записывайте код инициализации в одноименный отдельный файл. Например,
carrierwave.rb
,active_admin.rb
и т.д. [ссылка] -
Уточните настройки для рабочего (development), тестового (test) и промышленного (production) окружений в соответствующих файлах в директории
config/environments/
. [ссылка]-
Укажите добавленные вами ресурсы для комплиляции (при наличии):
# config/environments/production.rb # Скомпилируйте дополнительные ресурсы (application.js, application.css, # и прочие не JS/CSS уже добавлены). config.assets.precompile += %w( rails_admin/rails_admin.css rails_admin/rails_admin.js )
-
-
Сохраняйте настройки, которые относятся ко всем окружениям, в файле
config/application.rb
. [ссылка] -
Создайте дополнительное окружение
staging
, которое будет очень схоже с вашим окружениемproduction
. [ссылка] -
Храните любые дополнительные файлы конфиругации в формате
YAML
в директорииconfig/
. [ссылка]Начиная с
Rails 4.2
файлы конфиругации вYAML
можно легко загружать при помощи нового методаconfig_for
:Rails::Application.config_for(:yaml_file)
-
Если вам требуется добавить дополнительные действия к ресурсу REST (и вы уверены, что это вам абсолютно необходимо), то используйте пути
member
иcollection
. [ссылка]# плохо get 'subscriptions/:id/unsubscribe' resources :subscriptions # хорошо resources :subscriptions do get 'unsubscribe', on: :member end # плохо get 'photos/search' resources :photos # хорошо resources :photos do get 'search', on: :collection end
-
Когда вам нужно определить несколько контекстов маршрутизации при помощи
member
илиcollection
, используйте альтернативную блочную запись. [ссылка]resources :subscriptions do member do get 'unsubscribe' # дополнительные маршруты end end resources :photos do collection do get 'search' # дополнительные маршруты end end
-
Используйте вложенные определения маршрутов, чтобы лучше показать отношения между разными моделями
ActiveRecord
. [ссылка]class Post < ActiveRecord::Base has_many :comments end class Comments < ActiveRecord::Base belongs_to :post end # routes.rb resources :posts do resources :comments end
-
Если существует необходимость делать несколько уровней вложенности, то следует применять опцию
shallow: true
. Это оградит пользователя от длинных URLposts/1/comments/5/versions/7/edit
и вас от применения длинных наименований вродеedit_post_comment_version
.resources :posts, shallow: true do resources :comments do resources :versions end end
-
Используйте определенные в отдельном пространстве имен маршруты, чтобы объединить связанные действия. [ссылка]
namespace :admin do # Направляет /admin/products/* to Admin::ProductsController # (app/controllers/admin/products_controller.rb) resources :products end
-
Избегайте устаревшей обобщенной формы записи маршрутов. Такие маршруты откроют все действия во всех контроллерах для запросов
GET
. [ссылка]# очень плохо match ':controller(/:action(/:id(.:format)))'
-
Избегайте использования
#match
для определения маршрутов. Эта возможность удалена изRails 4
. [ссылка]
-
Поддерживайте код контроллеров обозримым, контроллеры должны лишь получать данные для шаблонов и не должны реализовывать бизнес-логику. Вся бизнес-логика вашего приложения должна по определению реализовываться в моделях. [ссылка]
-
Каждое действие в котроллере должно (в идеале) вызывать не более одного другого метода (кроме
#find
или#new
). [ссылка] -
Старайтесь не передавать более двух переменных из контроллера в шаблон. [ссылка]
-
Prefer using a template over inline rendering. [link]
# very bad class ProductsController < ApplicationController def index render inline: "<% products.each do |p| %><p><%= p.name %></p><% end %>", type: :erb end end # good ## app/views/products/index.html.erb <%= render partial: 'product', collection: products %> ## app/views/products/_product.html.erb <p><%= product.name %></p> <p><%= product.price %></p> ## app/controllers/foo_controller.rb class ProductsController < ApplicationController def index render :index end end
-
Prefer
render plain:
overrender text:
. [link]# bad - sets MIME type to `text/html` ... render text: 'Ruby!' ... # bad - requires explicit MIME type declaration ... render text: 'Ruby!', content_type: 'text/plain' ... # good - short and precise ... render plain: 'Ruby!' ...
-
Prefer corresponding symbols to numeric HTTP status codes. They are meaningful and do not look like "magic" numbers for less known HTTP status codes. [link]
# плохо # некоторый код render status: 500 # некоторый код # хорошо # некоторый код render status: :forbidden # некоторый код
-
Без зазрений совести используйте модели, не базирующиеся на
ActiveRecord
. [ссылка] -
Называйте модели говорящими (но короткими) именами без сокращений. [ссылка]
-
Если вам нужна модель, поддерживающая некоторые аспекты
ActiveRecord
(например, валидации), без привязки к работе с БД используйте библиотеку ActiveAttr. [ссылка]class Message include ActiveAttr::Model attribute :name attribute :email attribute :content attribute :priority attr_accessible :name, :email, :content validates :name, presence: true validates :email, format: { with: /\A[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i } validates :content, length: { maximum: 500 } end
Более подробный пример (на английском языке) вы найдете здесь: RailsCast #326: ActiveAttr.
-
Не расширяйте свои модели методами, которые реализуют форматирование данных (например, кодогенерацию HTML), кроме случаев, когда это напрямую связано с бизнес-логикой описываемой предметной области. Такие методы с большой вероятностью будут вызываться только из шаблонов представлений, поэтому их лучше разместить во вспомогательных модулях (helpers). Реализуйте в моделях только бизнес-логику и функционал работы с данными. [link]
-
Не меняйте стандартных значений
ActiveRecord
(например, наименования таблиц, первичных ключей и т.д.) без особой нужды. Это оправдано лишь в тех случаях, когда вы работаете с базой данных, схему которой (по разным причинам) нет возможности изменить. [ссылка]# плохо (не делайте так, если вы можете изменить схему) class Transaction < ActiveRecord::Base self.table_name = 'order' ... end
-
Группируйте макро-методы (
has_many
,validates
и т.д.) в начале определения класса. [ссылка]class User < ActiveRecord::Base # записывайте стандартную область видимости в начале (если имеется) default_scope { where(active: true) } # после этого записывайте константы COLORS = %w(red green blue) # далее следуют макросы доступа к атрибутам attr_accessor :formatted_date_of_birth attr_accessible :login, :first_name, :last_name, :email, :password # Энумераторы для `Rails >= 4` после макросов доступа, # предпочтительно использовать новых синтаксис для хешей. enum gender: { female: 0, male: 1 } # за которыми следуют макросы ассоциаций belongs_to :country has_many :authentications, dependent: :destroy # и макросы валидаций validates :email, presence: true validates :username, presence: true validates :username, uniqueness: { case_sensitive: false } validates :username, format: { with: /\A[A-Za-z][A-Za-z0-9._-]{2,19}\z/ } validates :password, format: { with: /\A\S{8,128}\z/, allow_nil: true } # после этого идут функции обратного вызова (callbacks) before_save :cook before_save :update_username_lower # оставшиеся макросы (например, Devise) дожны записываться в конце ... end
-
Используйте преимущественно
has_many :through
вместоhas_and_belongs_to_many
. Применение ассоциацииhas_many :through
дает вам большую свободу в определении дополнительных атрибутов и задании валидаций на модели объединения. [ссылка]# не особо (применяется has_and_belongs_to_many) class User < ActiveRecord::Base has_and_belongs_to_many :groups end class Group < ActiveRecord::Base has_and_belongs_to_many :users end # предпочтительное решение (применяется has_many :through) class User < ActiveRecord::Base has_many :memberships has_many :groups, through: :memberships end class Membership < ActiveRecord::Base belongs_to :user belongs_to :group end class Group < ActiveRecord::Base has_many :memberships has_many :users, through: :memberships end
-
Используйте
self[:attribute]
вместоread_attribute(:attribute)
. [ссылка]# плохо def amount read_attribute(:amount) * 100 end # хорошо def amount self[:amount] * 100 end
-
Преимущественно используйте
self[:attribute] = value
вместоwrite_attribute(:attribute, value)
. [ссылка]# плохо def amount write_attribute(:amount, 100) end # хорошо def amount self[:amount] = 100 end
-
Всегда применяйте новый синтаксис валидаций, так называемые "sexy" validations . [ссылка]
# плохо validates_presence_of :email validates_length_of :email, maximum: 100 # хорошо validates :email, presence: true, length: { maximum: 100 }
-
Если определенная разработчиком валидация используется несколько раз или содержит сложные (регулярные) выражения, то стоит ее вынести в отдельный файл валидаторов. [ссылка]
# плохо class Person validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i } end # хорошо class EmailValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) record.errors[attribute] << (options[:message] || 'is not a valid email') unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i end end class Person validates :email, email: true end
-
Храните файлы определенных вами валидаторов в
app/validators
. [ссылка] -
Подумайте о том, чтобы выделить ряд определенных вами валидаторов в отдельный гем, если вы работаете над несколькими схожими приложениями и валидаторы имеют достаточно обобщенные функции. [ссылка]
-
Спокойно применяйте поименованные области поиска (named scopes). [ссылка]
class User < ActiveRecord::Base scope :active, -> { where(active: true) } scope :inactive, -> { where(active: false) } scope :with_orders, -> { joins(:orders).select('distinct(users.id)') } end
-
Если поименованная область поиска определяется с помощью
lambda
с дополнительными параметрами, то такая запись очень быстро может стать слишком сложной. В таком случае лучше определить метод класса, который будет служить той же цели и возвращать объект классаActiveRecord::Relation
. Наверное, этим же образом можно определять и более простые области поиска. [ссылка]class User < ActiveRecord::Base def self.with_orders joins(:orders).select('distinct(users.id)') end end
-
Поймите принцип работы метода
update_attribute
. Он не вызывает валидации моделей (в отличие отupdate_attributes
) и может быстро привести к появлению ошибочных записей в базе данных. [ссылка] -
Используйте дружественную пользователю запись URL. Указывайте в URL какой-то говорящий сам за себя атрибут модели, а не
id
. Есть несколько путей для достижения такого результата: [ссылка]-
Переопределите метод
to_param
в модели. Это метод используется вRails
для генерирования URL к объекту. Стандартная реализация возвращаетid
объекта (записи) в виде строки. Это поведение можно переопределить и включить некоторый понятный человеку атрибут.class Person def to_param "#{id} #{name}".parameterize end end
Чтобы преобразовать эту форму в более адекватную для URL, нужно вызвать метод
parameterize
на строковом объекте. Идентификаторid
объекта должен быть в начале строки, чтобы его мог найти методfind
библиотекиActiveRecord
. -
Используйте гем
friendly_id
. Эта библиотека создает легко читаемые URL с использованием некоторых говорящих атрибутов моделей вместоid
.class Person extend FriendlyId friendly_id :name, use: :slugged end
Изучите документацию гема, чтобы лучше разобраться в его применении.
-
-
Используйте
find_each
для обхода коллекций объектовActiveRecord
. Перебор объектов записей базы данных в цикле (например, с использованием методаall
) крайне неэффективен, так как в данном случае в памяти будут созданы все интересующие нас объекты за раз. Для такого рода задач больше подходит пакетная обработка, при которой методы вызывают записи порциями, что значительно сокращает расход памяти. [ссылка]# плохо Person.all.each do |person| person.do_awesome_stuff end Person.where("age > 21").each do |person| person.party_all_night! end # хорошо Person.all.find_each do |person| person.do_awesome_stuff end Person.where("age > 21").find_each do |person| person.party_all_night! end
-
Rails создает методы обратного вызова для зависимых ассоциаций, поэтому всегда вызывайте метод
before_destroy
для валидации с параметромprepend: true
. [ссылка]# плохо (роли будут удалены в любом случае, даже если super_admin? задан) has_many :roles, dependent: :destroy before_destroy :ensure_deletable def ensure_deletable fail "Cannot delete super admin." if super_admin? end # хорошо has_many :roles, dependent: :destroy before_destroy :ensure_deletable, prepend: true def ensure_deletable fail "Cannot delete super admin." if super_admin? end
-
Задавайте опцию
dependent
в ассоциация типаhas_many
иhas_one
. [link]# плохо class Post < ActiveRecord::Base has_many :comments end # хорошо class Post < ActiveRecord::Base has_many :comments, dependent: :destroy end
-
Избегайте интерполяции строк в запросах, это сделает ваш код менее уязвимым к атакам типа
SQL injection
. [ссылка]# плохо (param будет вставлен без экранирования) Client.where("orders_count = #{params[:orders]}") # хорошо (param будет экранирован должным образом) Client.where('orders_count = ?', params[:orders])
-
Предпочитайте поименованные подстановки вместо позиционных подстановок, если у вас в запросе их более двух. [ссылка]
# сойдет Client.where( 'created_at >= ? AND created_at <= ?', params[:start_date], params[:end_date] ) # хорошо Client.where( 'created_at >= :start_date AND created_at <= :end_date', start_date: params[:start_date], end_date: params[:end_date] )
-
Отдавайте предпочтение использованию
find
вместоwhere
, если вам нужно получить всего одну запись по ее идентификатору. [ссылка]# плохо User.where(id: id).take # хорошо User.find(id)
-
Отдавайте предпочтение использованию
find_by
вместоwhere
иfind_by_attribute
, если вам нужно получить всего одну запись по значению какого-то ее атрибута. [ссылка]# плохо User.where(first_name: 'Bruce', last_name: 'Wayne').first # плохо User.find_by_first_name_and_last_name('Bruce', 'Wayne') # хорошо User.find_by(first_name: 'Bruce', last_name: 'Wayne')
-
Используйте
where.not
вместо простого SQL. [ссылка]# плохо User.where("id != ?", id) # хорошо User.where.not(id: id)
-
При явном формулировании запроса в таких методах, как
find_by_sql
, используйте HEREDOC в сочетании с методомsquish
. Это позволит вам оформить код SQL читаемым образом с переносами строк и отступами и сохранит подержку подсветки синтаксиса на большинстве платформ (GitHub, Atom, RubyMine). [link]User.find_by_sql(<<SQL.squish) SELECT users.id, accounts.plan FROM users INNER JOIN accounts ON accounts.user_id = users.id # прочие детали... SQL
String#squish
удаляет отступы и переносы, таким образом запросы будут отображаться в виде обычных строк, а не в виде вот таких последовательностей:SELECT\n users.id, accounts.plan\n FROM\n users\n INNER JOIN\n acounts\n ON\n accounts.user_id = users.id
-
Храните файл
schema.rb
(илиstructure.sql
) в вашей системе управления версиями. [ссылка] -
Используйте вызов
rake db:schema:load
вместоrake db:migrate
для инициализации пустой базы данных. [ссылка] -
Устанавливайте стандартные значения в миграциях, а не в бизнес-логике вашего приложения. [ссылка]
# плохо (стандартное значение устанавливается в приложении) def amount self[:amount] or 0 end
Многие опытные разработчики на
Rails
рекомендуют устанавливать стандартные значения только на уровне приложения и миграций, однако этот подход скрывает множество уязвимостей и потенциальных ошибок. Кроме этого, стоит рассмотреть тот момент, что большиство сложных приложений используют одну совместную базу данных вместе с другими приложениями, поэтому логика проверки, реализованная в приложении наRails
, будет недоступа из других приложений. -
Устанавливайте ограничения на внешние ключи. Начиная с
Rails 4.2
библиотекаActiveRecord
поддерживает внешние ключи напрямую. [ссылка] -
При написании миграций для добавления таблиц или столбцов создавайте метод
change
вместо методовup
иdown
. [ссылка]# старый способ class AddNameToPeople < ActiveRecord::Migration def up add_column :people, :name, :string end def down remove_column :people, :name end end # новый предпочтительный способ class AddNameToPeople < ActiveRecord::Migration def change add_column :people, :name, :string end end
-
Не используйте классы моделей в миграциях. Классы моделей постоянно меняются, неизбежно наступит момент, когда код миграций перестанет работать из-за изменений в модели, хотя ранее этот код работал без проблем. [ссылка]
-
Ни при каких условиях не следует работать с моделями напрямую из представлений. [ссылка]
-
Избегайте сложной логики в представлениях, выделяйте этот код во вспомогательные методы представлений (view helpers) или выносите их в модель. [ссылка]
-
Избегайте повторений кода, используйте отдельные шаблоны и подшаблоны представлений. [ссылка]
-
Строки и другие локальные настройки и детали следует выносить из представлений и контроллеров, а также моделей в файлы для конкретных локалей в директории
config/locales
. [ссылка] -
Когда вам нужно перевести идентификаторы для моделей ActiveRecord, применяйте контекст
activerecord
: [ссылка]en: activerecord: models: user: Member attributes: user: name: 'Full name'
В этом случае
User.model_name.human
вернет'Member'
иUser.human_attribute_name('name')
вернет'Full name'
. Переводы этих атрибутов будут использоваться в качестве идентификаторов в представлениях. -
Разделяйте файлы с переводами представлений от переводов атрибутов
ActiveRecord
. Размещайте файлы локалей для моделей в директорииlocales/models
, а используемые в представлениях тексты в директорииlocales/views
. [ссылка]-
Если файлы локалей сохраняются в дополнительных директориях, то пути к ним должны быть определены в файле
application.rb
, чтобы файлы локалей могли быть загружены.# config/application.rb config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
-
-
Размещайте общие параметры локализации, например, форматы записи дат и валют, в файлах в корне директории
locales
. [ссылка] -
Используйте краткую форму методов
I18n
:I18n.t
вместоI18n.translate
иI18n.l
вместоI18n.localize
. [ссылка] -
Используйте "ленивый" подход к поиску текстов в представлениях. Допустим, у вас есть следующая структура: [ссылка]
en: users: show: title: 'User details page'
Значение для
users.show.title
можно будет найти в шаблонеapp/views/users/show.html.haml
, например, так:= t '.title'
-
Задавайте ключи в контроллерах и моделях при помощи разделения точками, а не с помощью опции
:scope
. Разделенные точками вызовы проще читать, их иерархия более понятна. [ссылка]# плохо I18n.t :record_invalid, scope: [:activerecord, :errors, :messages] # хорошо I18n.t 'activerecord.errors.messages.record_invalid'
-
Более подробную информацию по интернационализации (I18n) в Rails можно найти по адресу API интернационализации Rails либо Rails Guides (английский оригинал). [ссылка]
Применяйте конвейер ресурсов (assets pipeline) для упорядочения структуры вашего приложения.
-
Зарезервируйте директорию
app/assets
для ваших собственных таблиц стилей, скриптов и/или изображений. [ссылка] -
Используйте директорию
lib/assets
для ваших собственных библиотек, которые не реализуют первичный функционал вашего приложения. [ссылка] -
Код сторонних библиотек, например, jQuery или bootstrap, следует размещать в директории
vendor/assets
. [ссылка] -
По возможности используйте упакованные версии необходимых ресурсов, например: [ссылка]
-
Называйте почтовые модули по образцу
SomethingMailer
. Без суффиксаMailer
не сразу будет понятно, что это почтовый модуль и какие представления связаны с этим модулем. [ссылка] -
Создавайте шаблоны представлений в текстовом формате и в формате HTML. [ссылка]
-
Включите вызов ошибок при проблемах с доставкой почты в вашем окружении для разработки. По умолчанию эти вызовы отключены. [ссылка]
# config/environments/development.rb config.action_mailer.raise_delivery_errors = true
-
Используйте локальный сервер SMTP, например, Mailcatcher в вашем окружении разработки. [ссылка]
# config/environments/development.rb config.action_mailer.smtp_settings = { address: 'localhost', port: 1025, # more settings }
-
Указывайте стандартные настройки имени вашего узла. [ссылка]
# config/environments/development.rb config.action_mailer.default_url_options = { host: "#{local_ip}:3000" } # config/environments/production.rb config.action_mailer.default_url_options = { host: 'your_site.com' } # в вашем классе мейлера default_url_options[:host] = 'your_site.com'
-
Если вам нужно указать ссылку на ваш сайт в тексте письма, всегда используйте методы с суффиксом
_url
, а не_path
. Методы с суффиксом_url
включают имя вашего узла в текст ссылки, а с суффиксом_path
не включают. [ссылка]# плохо You can always find more info about this course <%= link_to 'here', course_path(@course) %> # хорошо You can always find more info about this course <%= link_to 'here', course_url(@course) %>
-
Записывайте адреса отправителя и получателя должным образом. Используйте следующий формат: [ссылка]
# в классе мейлера default from: 'Your Name <info@your_site.com>'
-
Убедитесь в том, что метод доставки писем в вашем тестовом окружении обозначен как
test
: [ссылка]# config/environments/test.rb config.action_mailer.delivery_method = :test
-
Методом доставки почты для разработки и развертывания должен быть
smtp
: [ссылка]# config/environments/development.rb, config/environments/production.rb config.action_mailer.delivery_method = :smtp
-
При рассылке электронной почты в формате HTML все описания стилей должны быть включены в текст, потому что некоторые почтовые программы неверно обрабатывают внешние таблицы стилей. Однако, это приводит к сложностям в поддержке таких таблиц и повторениям в коде. Для преобразования и внедрения стилей в текст письма существую два схожим по функциональности гема: premailer-rails и roadie. [ссылка]
-
Избегайте рассылки почты параллельно к генерации страницы в ответ на запрос пользователя. Это вызовет задержки в загрузке страницы, и запрос может быть отклонен из-за превышения таймаута, если вы рассылаете много писем. Вы можете преодолеть данное ограничение, вызывая процессы рассылки в фоне, например, при помощи гема sidekiq. [ссылка]
-
Prefer Ruby 2.3's safe navigation operator
&.
overActiveSupport#try!
. [link]# bad obj.try! :fly # good obj&.fly
-
Prefer Ruby's Standard Library methods over
ActiveSupport
aliases. [link]# bad 'the day'.starts_with? 'th' 'the day'.ends_with? 'ay' # good 'the day'.start_with? 'th' 'the day'.end_with? 'ay'
-
Prefer Ruby's Standard Library over uncommon ActiveSupport extensions. [link]
# bad (1..50).to_a.forty_two 1.in? [1, 2] 'day'.in? 'the day' # good (1..50).to_a[41] [1, 2].include? 1 'the day'.include? 'day'
-
Prefer Ruby's comparison operators over
ActiveSupport
Array#inquiry
,Numeric#inquiry
andString#inquiry
. [link]# bad - String#inquiry ruby = 'two'.inquiry ruby.two? # good ruby = 'two' ruby == 'two' # bad - Array#inquiry pets = %w(cat dog).inquiry pets.gopher? # good pets = %w(cat dog) pets.include? 'cat' # bad - Numeric#inquiry 0.positive? 0.negative? # good 0 > 0 0 < 0
-
Настройте в файле
application.rb
вашу временную зону. [ссылка]config.time_zone = 'Eastern European Time' # опционально (обратите внимание, возможны только значения :utc или :local, # по умолчанию :utc) config.active_record.default_timezone = :local
-
Не используйте
Time.parse
. [ссылка]# плохо # Подразумевается, что передаваемая строка со временем отражает временную зону вашей ОС. Time.parse('2015-03-02 19:05:37') # хорошо Time.zone.parse('2015-03-02 19:05:37') # => Mon, 02 Mar 2015 19:05:37 EET +02:00
-
Не используйте
Time.now
. [ссылка]# плохо # Возвращает системное время и не учитывает настройки временной зоны. Time.now # хорошо Time.zone.now # => Fri, 12 Mar 2014 22:04:47 EET +02:00 Time.current # Более короткая форма записи.
-
Держите гемы, которые используются только для разработки и/или тестирования в соответствующих группах вашего
Gemfile
. [ссылка] -
Применяйте в своих проектах только рекомендованные временем библиотеки. Если вы задумываетесь, не включить ли в проект малоизвестный гем, вам следует сперва внимательно просмотреть его исходных код. [ссылка]
-
Системозависимые библиотеки в вашем проекте будут причиной постоянного изменения файла
Gemfile.lock
для проектов с несколькими разработчиками, работающими на разных операционных системах. Поэтому внесите все библиотеки, написанные дляOS X
, в группуdarwin
, а библиотеки, написанные дляLinux
, в группуlinux
. [ссылка]# Gemfile group :darwin do gem 'rb-fsevent' gem 'growl' end group :linux do gem 'rb-inotify' end
Для включения нужных библиотек только в нужном окружении, добавьте в файл
config/application.rb
следующие строки:platform = RUBY_PLATFORM.match(/(linux|darwin)/)[0].to_sym Bundler.require(platform)
-
Сохраняйте файл
Gemfile.lock
в вашей системе управления версиями. Этот файл содержит неслучайную информацию. Так вы сможете удостовериться, что все члены вашей команды установят точно те же версии библиотек, что и вы, при помощи командыbundle install
. [ссылка]
- Если в вашем проекте есть много зависимостей от внешних процессов, применяйте библиотеку foreman для управления ими. [ссылка]
Существует несколько отличных источников по стилю оформления приложений
на Rails
, на которые вы можете взглянуть, если у вас будет свободное время:
- The Rails 4 Way
- Ruby on Rails Guides
- The RSpec Book
- The Cucumber Book
- Everyday Rails Testing with RSpec
- Better Specs for RSpec
Ничто, описанное в этом руководстве, не высечено в камне. И я очень хотел бы сотрудничать со всеми, кто интересуется стилистикой оформления кода Rails, чтобы мы смогли вместе создать ресурс, который был бы полезен для всего сообщества программистов на Руби.
Не стесняйтесь создавать отчеты об ошибках и присылать мне запросы на интеграцию вашего кода. И заранее большое спасибо за вашу помощь!
Вы можете поддержать проект (и РубоКоп) денежным взносом при помощи gittip.
Это просто! Просто следуйте руководству по сотрудничеству.
Данная работа опубликована на условиях лицензии Creative Commons Attribution 3.0 Unported License
Создаваемое сообществом руководство по стилю оформления будет малопригодным для сообщества, которое об этом руководстве ничего не знает. Делитесь ссылками на это руководство с вашими друзьями и коллегами доступными вам средствами. Каждый получаемый нами комментарий, предложение или мнение сделает это руководство еще чуточку лучше. А ведь мы хотим самое лучшее руководство из возможных, не так ли?
Всего,
Божидар