持続可能なRailsアプリを目指して。
基本的に、Ruby on Rails Guides (En / Jp) に従ってください。
基本的に、普通のRubyのライブラリやアプリケーションを書くときの作法に従ってください。
基本的に、RuboCopのルールに従ってください。
RuboCopで表現可能なルールについては、このガイドラインでは説明しておらず、RuboCopの設定やカスタムCopとして表現されています。
あるべきところにあるべきコードが記述されているような、驚きの少ないコードを目指してください。
READMEを見るだけで開発環境を構築できるようにしてください。
リクエストの処理中に不要なSQL等が発行されていないか、常に確認してください。
メソッドが引数または返り値を持つ場合、期待する型をYARDで記述してください。
悪い例:
def call(foo:)
foo.bar(baz)
end
良い例:
# @param [Foo] foo
# @return [String]
def call(foo:)
foo.bar(baz)
end
ファイルパスまたは命名規則がRailsに規定されていない限り、ドメインモデルはすべて app/models
に置いてください。
ユーザー体験を向上させるためにも、ActiveModelやActiveRecordのモデルでは適切にValidationを利用してください。
RESTfulなエンドポイント、コントローラー名、アクション名を使ってください。
悪い例:
get '/user_status/:user_id', to: 'users#status'
良い例:
get '/users/:user_id/status', to: 'user_statuses#show'
不要なルーティングパターンや不要なURLヘルパーを定義しないでください。
悪い例:
resources :articles
get '/foos/:foo_id/bar'
良い例:
resources :articles, only: %i[index show]
get '/foos/:foo_id/bar', as: nil
アクションの主な処理より前にレスポンスを返すときは、before_actionを使ってください。
悪い例:
def index
if signed_in?
redirect_to sign_in_path
return
end
# ...
end
良い例:
before_action :require_signed_in
def index
# ...
end
private
def require_signed_in
if signed_in?
redirect_to sign_in_path
end
end
利用するステータスコードの種類は、アプリや機能単位で統一してください。
悪い例:
if @article.update(attributes)
redirect_to @article
else
render 'update_error'
end
良い例:
if @article.update(attributes)
redirect_to @article
else
render 'update_error', status: 422
end
ActionController::Parameters
のインスタンスをメソッドの引数に渡さないでください。
悪い例:
Foo.call(foo_params)
良い例:
Foo.call({ a: foo_params[:a], b: foo_params[:b] })
良い例:
Foo.call(foo_params.to_h)
describe
や context
のネストを浅く保ってください。
悪い例:
context 'Aのとき' do
# ...
end
context 'Aでないとき' do
context 'Bのとき' do
# ...
end
end
良い例:
context 'Aのとき' do
# ...
end
context 'Bのとき' do
# ...
end
その自然言語の文法規則に従い、適切な形式でテストメッセージを記述してください。
悪い例:
it 'AがBになること' do
# ...
end
良い例:
it 'AをBにする' do
# ...
end
describe
とその直下の subject
、また context
とその直下の before
とを対応させてください。
悪い例:
context 'when article is unpublished' do
it '...' do
article.published_at = nil
# ...
end
end
良い例:
context 'when article is unpublished' do
before do
article.published_at = nil
end
# ...
end
1つのアクションに対して、1つのrequest-specのテストファイルを用意してください。
悪い例:
# spec/requests/articles_spec.rb
RSpec.describe 'Articles' do
describe 'GET /articles' do
# ...
end
describe 'GET /articles/:id' do
# ...
end
end
良い例:
# spec/requests/articles_index_spec.rb
RSpec.describe 'GET /articles' do
# ...
end
# spec/requests/articles_show_spec.rb
RSpec.describe 'GET /articles/:id' do
# ...
end
JSON形式のレスポンスボディ等を検査する場合、match matcherを利用してください。
悪い例:
expect(response.parsed_body['comments']['id']).to eq(comment.id)
良い例:
expect(response.parsed_body).to match(
'comment' => hash_including(
'id' => comment.id
)
)
複数件のレコードが利用されるテストを記述するとき、事前条件として2件以上のレコードをつくってください。
悪い例:
before do
FactoryBot.create(:article)
end
良い例:
before do
FactoryBot.create_list(:article, 2)
end
基本的に、controller-specを避け、request-specを使ってください。
悪い例:
# spec/controllers/articles_controller_spec.rb
RSpec.describe ArticlesController do
describe '#index' do
# ...
end
end
良い例:
# spec/requests/articles_index_spec.rb
RSpec.describe 'GET /articles' do
# ...
end
高価なsystem-specで保証する必要がある箇所にのみ、system-specを利用してください。
何かを宣言するコードについて、それを宣言しているかどうかを検査するだけのテストを記述しないでください。
悪い例:
class Article < ApplicationRecord
validates :title, presence: true
end
RSpec.describe Article do
it do
is_expected.to validate_presence_of(:title)
end
end