Skip to content
日本語訳:Railsスタイルガイド
Branch: master
Clone or download
Pull request Compare This branch is 3 commits ahead, 232 commits behind rubocop-hq:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
README.md

README.md

序曲

役割モデルが重要なのだ。
-- アレックス・マーフィー巡査 / ロボコップ

このガイドのゴールは、Ruby on Rails 3と4開発のための1セットのベストプラクティスおよびスタイル規則を示すことです。これは、コミュニティー駆動ですでに存在する Ruby coding style guide の補足的なガイドです。

ガイドの中では「Railsアプリケーションのテスト」は「Railsアプリケーション開発」の後にあります。私は、振る舞い駆動開発 (BDD) がソフトウェアを開発する最良の方法であると本当に信じています。それを覚えておいてください。

Railsは信念の強いフレームワークです。そしてこれは信念の強いガイドです。心の中では、RSpecがTest::Unitより優れていると完全に確信しています。SassはCSSより優れています。そして、Haml (Slim)はErbより優れています。したがって、Test::Unit、CSS、Erbに関するどんな助言も、この中で見つけることは期待できません。

ここにある助言うちのいくつかは、Rails 3.1以上でのみ適用できます。

Transmuterを使用して、PDFあるいはこのガイドのHTMLコピーを生成することができます。

このガイドには次の言語の翻訳版があります。

目次

Railsアプリケーション開発

設定

  • config/initializersにカスタム初期化コードを入れてください。initializersの中のコードはアプリケーション起動時に実行されます。

  • 各gemの初期化コードは、gemと同じ名前の個別のファイルを維持してください。例えば、carrierwave.rbactive_admin.rbなどです。

  • development、test、productionの各環境の設定 (config/environments/の下の対応するファイル) に従って調節します。

    • (もしあれば) プリコンパイルの追加アセットを記します。

      ```Ruby
      # config/environments/production.rb
      # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
      config.assets.precompile += %w( rails_admin/rails_admin.css rails_admin/rails_admin.js )
      ```
      
  • config/application.rb では、すべての環境に適用可能な設定をしてください。

  • production環境に似た、staging環境を追加で作成してください。

ルーティング

  • RESTfulリソース (本当に必要ですか?) に対して、さらにアクションを追加する必要がある場合、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'
        # more routes
      end
    end
    
    resources :photos do
      collection do
        get 'search'
        # more routes
      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
  • 関連するアクションをグループ化するためにnamespaceを使用してください。

    namespace :admin do
      # Directs /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以外、(理想的には) 1つのメソッドだけを起動するべきです。
  • コントローラーとビューの間の変数の共有は、2つを超えない範囲にしてください。

モデル

ActiveRecord

  • 非常に十分な理由 (あなたの管理下にないデータベースを使用する場合など) がない限りは、ActiveRecordデフォルト (テーブル名、主キーなど) を変更しないようにしてください。

    # 悪い - スキーマを修正できるのなら、このようにしないでください。
    class Transaction < ActiveRecord::Base
      self.table_name = 'order'
      ...
    end
  • マクロスタイルのメソッド (has_many, validates, など) はクラス定義の始めにまとめてください。

    class User < ActiveRecord::Base
      # デフォルトスコープは最初に(あれば)
      default_scope { where(active: true) }
    
      # 続いて定数
      GENDERS = %w(male female)
    
      # その後attr関係のマクロを置きます
      attr_accessor :formatted_date_of_birth
    
      attr_accessible :login, :first_name, :last_name, :email, :password
    
      # 関連マクロが続きます
      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}
    
      # 次にコールバックです
      before_save :cook
      before_save :update_username_lower
    
      # その他のマクロ(deviseなど)はコールバックの後に置かれるべきです
    
      ...
    end
  • has_and_belongs_to_manyよりもhas_many :throughを好んでください。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
  • read_attribute(:attribute)よりもself[:attribute]を好んでください。

    # 悪い
    def amount
      read_attribute(:amount) * 100
    end
    
    # 良い
    def amount
      self[:amount] * 100
    end
  • 常に新しい "sexy" validations を使用してください。

    # 悪い
    validates_presence_of :email
    
    # 良い
    validates :email, presence: true
  • カスタムバリデーションが2度以上使用されるか、バリデーションが正規表現マッチングである場合は、カスタムバリデータファイルを作成してください。

    # 悪い
    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に置いてください。

  • あなたが複数の関連するアプリケーションをメンテンスしているか、バリデータが十分に一般的であるならば、共有されるgemへカスタムバリデータを抽出することを検討してください。

  • named scopeは自由に使用してください。

    class User < ActiveRecord::Base
      scope :active, -> { where(active: true) }
      scope :inactive, -> { where(active: false) }
    
      scope :with_orders, -> { joins(:orders).select('distinct(users.id)') }
    end
  • 遅延初期化のためにnamed scopeをlambdasで包んでください。(Rails 3では単なる処方箋ですが、Rails 4では必須です。)

    # 悪い
    class User < ActiveRecord::Base
      scope :active, where(active: true)
      scope :inactive, where(active: false)
    
      scope :with_orders, joins(:orders).select('distinct(users.id)')
    end
    
    # 良い
    class User < ActiveRecord::Base
      scope :active, -> { where(active: true) }
      scope :inactive, -> { where(active: false) }
    
      scope :with_orders, -> { joins(:orders).select('distinct(users.id)') }
    end
  • ラムダとパラメータを使用したnamed scope定義が複雑になる場合、named scopeと同じ目的のために、代わりにActiveRecord::Relationオブジェクトを返すクラスメソッドを作るのは望ましいことです。恐らくこのようにさらに単純なscopeを定義することができます。

    class User < ActiveRecord::Base
      def self.with_orders
        joins(:orders).select('distinct(users.id)')
      end
    end
  • update_attributeメソッドの振る舞いに用心してください。これはモデルバリデーションを実行せず (update_attributesと異なる)、容易にモデルの状態を悪くするかもしれません。このメソッドは最終的にRails 3.2.7で非推奨となり、Rails 4では存在しません。

  • ユーザー・フレンドリーなURLを使用してください。URLの中ではモデルのidではなく、モデルの記述的な属性を表示してください。このためのいくつかの方法があります。

    • to_paramメソッドをオーバーライドしてください。これはオブジェクトへのURLを構築するためにRailsによって使用されます。デフォルト実装では、レコードのidを文字列として返します。他の「人間が判読可能な」属性を含めるために、これをオーバーライドすることができます。

      ```Ruby
      class Person
        def to_param
          "#{id} #{name}".parameterize
        end
      end
      ```
      URLフレンドリーな値に変換するために、文字列の`parameterize`を呼ぶ必要があります。ActiveRecordの`find`メソッドで見つけることができるように、オブジェクトの`id`が始めにある必要があります。
      
    • friendly_id gemを使用してください。これは、そのidの代わりにモデルの記述的な属性を使用することによって、人間が判読可能なURLを生成できるようにします。

      ```Ruby
      class Person
        extend FriendlyId
        friendly_id :name, use: :slugged
      end
      ```
      
      使い方について、より詳細は [gemドキュメント](https://github.com/norman/friendly_id) を確認してください。
      

マイグレーション

ビュー

  • ビューからモデル層を直接呼び出さないでください。
  • ビューの中で複雑な体裁出力を作らないでください。ビューヘルパー、またはモデルのメソッドに体裁を出してください。
  • 部分テンプレートやレイアウトを使用してコードの重複を軽減させてください。

国際化

アセット

アプリケーション内の構成にてこ入れするためにアセットパイプラインを使用してください。

  • カスタムのstyleshees, javascripts, imagesのためにapp/assetsを使用してください。
  • あなたが所有するライブラリにはlib/assetsを使用してください。アプリケーションのスコープに入りません。
  • jQuerybootstrap のような第三者のコードはvendor/assetsに置かれるべきです。
  • 可能な場合は、アセットをgem化したバージョンを使用してください。(例:jquery-rails, jquery-ui-rails, bootstrap-sass, zurb-foundation). )

Mailer

Bundler

  • 開発またはテストのみ使用されるgemは、Gemfileの適切なグループの中に置いてください。

  • プロジェクトでは定評のあるgemだけ使用してください。ほとんど知られていないgemを含めることを検討しているのなら、そのソースコードの注意深い調査を最初に行うべきです。

  • OS特有のgemは、異なるOSを使用している複数の開発者と一緒のプロジェクトのために、頻繁に変わるGemfile.lockによって得ます。OS Xの特有のgemをすべてGemfileの中のdarwinグループに、Linux特有のgemをlinuxグループに加えてください。

    # Gemfile
    group :darwin do
      gem 'rb-fsevent'
      gem 'growl'
    end
    
    group :linux do
      gem 'rb-inotify'
    end

    正しい環境で適切なgemを要求するためには、config/application.rbに以下を加えてください。

    platform = RUBY_PLATFORM.match(/(linux|darwin)/)[0].to_sym
    Bundler.require(platform)
  • バージョン管理からGemfile.lockを取り除かないでください。これは任意に生成されたファイルではありません。- これはbundle installした時に、チームメンバーが確実にすべて同じgemバージョンを得るためのものです。

有用なgem

最も重要なプログラミングの法則の1つはこうです。「車輪を再発明するな!」。あるタスクに直面した時には、自分のものを広げる前に、常に既存の解決策を見つけるために周りを見回すべきです。ここにあるリストは、多くのRailsプロジェクトに役立つ「有用な」gemです。(すべてRails 3.1準拠)

  • active_admin - ActiveAdminがあれば、Railsアプリにおける管理者インタフェースの作成は子供の遊びのようなものです。素敵なダッシュボード、CRUD UI、その他いろいろ。とても柔軟でカスタマイズ可能です。
  • better_errors - Better ErrorsはRailsのエラーページをより良く有益なページに取り替えます。Rackミドルウェアとして、Railsの外で使用できます。
  • bullet - The Bulletは、アプリケーションが作るクエリの数を減らすことによって、パフォーマンス向上に役立つように設計されています。あなたがアプリケーションを開発している間、一括読み込み(N+1クエリ)をいつ加えなければならないか、また、いつ必要でない一括読み込みを使用するか、いつカウンタキャッシュを使用しなければならないかを通知します。
  • cancan - CanCanは、リソースへのユーザーのアクセスを制限させることができる認証gemです。べての権限は、単一のファイル(ability.rb)で定義され、アクセス権をチェックし確保するための便利な方法は、アプリケーション全体で利用できます。
  • capybara - Capybaraは、Rails、Sinatra、MerbのようなRackアプリケーションにおける統合テストのプロセスを単純化することを目標としています。CapybaraはリアルユーザーのWebアプリケーションとの対話をシミュレートします。それはテストを実行するドライバーに関して不可知論者で、Rack::Testに付属し、Seleniumをビルトインでサポートしています。HtmlUnit、WebKit、env.jsは外部gemによってサポートされます。RSpecとCucmberとのコンビネーションで素晴らしい仕事をします。
  • carrierwave - Railsにおける究極のファイルアップロードソリューション。アップロードファイルはローカルと、クラウドストレージの両方をサポートします。画像の後処理のためにImageMagickと素晴らしく統合します。
  • compass-rails - いくつかのCSSフレームワークのサポートを追加する、素晴らしいgem。CSSファイルのコードが削減され、ブラウザ非互換性との戦いを助けるsaas mixinsのコレクションが含まれています。
  • cucumber-rails - Cucumber はRubyで機能テストを開発するプレミアムツールです。cucumber-railsは、RailsへのCucumberの統合を提供します。
  • devise - Deviseは、Railsアプリケーションのフル機能の認証ソリューションです。 カスタム認証ソリューションを展開するほとんどの場合、Deviseの使用が適しています。
  • fabrication - 素晴らしいfixtureの代替 (editor's choice).
  • factory_girl - fabricationの代わり。とても成熟したfixtureの代替です。fabricationの精神を持っています。
  • ffaker - ダミーデータを生成する手軽なgem。(氏名、住所、その他)
  • feedzirra - とても高速で柔軟なRSS/Atomフィードのパーサー。
  • friendly_id - モデルのIDの代わりに記述的な属性を使って、人間が読めるURLを生成します
  • globalize - ActiveRecordのモデル/データ変換のためのRails国際化のデファクトスタンダードのライブラリです。Railsのグローバル化とActiveRecordのバージョン4.xを対象としています。これは、Ruby on Railsの新しいI18n APIと互換性があり、ActiveRecordのためのモデルの変換が追加されます。ActiveRecord 3.xのユーザーは、3-0-stable branch を確認してください。
  • guard - ファイルの変更を監視し、それに基づいたタスクを起動する、素晴らしいgemです。多くの有用な拡張が載せられました。自動テストとwatchrよりはるかに優れています。
  • haml-rails - haml-railsは、HamlのRailsへの統合を提供します。
  • haml - HAMLは簡潔なテンプレート言語で、多くの人に (あなたも含まれます) Erbよりはるかに優れいていると考えられています。
  • kaminari - 素晴らしいページングソリューション。
  • machinist - fixtureは楽しくありません。mechanistなら。
  • rspec-rails - RSpecはTest::MiniTestの代替です。私はRSpecを十分に強く推奨することができません。rspec-railsは、RSpecのRailsへの統合を供給します。 sidekiq - SidekiqはRailsアプリでバックグラウンドジョブを実行するための、おそらく最も簡単で拡張性の高い方法です。
  • simple_form - 一度simple_form (あるいはformtastic) を使用したならば、あなたは決してRailsのデフォルト形式に関して聞かされたくありません。フォームを構築するためにマークアップに対して文句のない素晴らしいDSLを持っています。
  • simplecov-rcov - SimpleCovのためのRCovフォーマッタ。Hudsonのcontininousな統合サーバーとSimpleCovを使用しようとしているなら有用です。
  • simplecov - コードカバレッジツール。RCovと異なり、Ruby 1.9と完全に互換性をもちます。素晴らしいレポートを生成します。必携!
  • slim - Slimは簡潔なテンプレート言語です。HAMLより優れています (Erbには言及しない)。私が使用するのを止める重くて細いただ1つの理由は、主要なエディタ/IDEのサポートの不足です。そのパフォーマンスは驚異的です。
  • spork - フレームワーク (現状、RSpec/Cucumber) をテストするためのDRbサーバです。クリーンなテスト状態を保障するために各々の実行前にフォークします。簡単に言えば、多くのテスト環境を事前ロードします。その結果として、テストの最初の時間が大幅に減少します。絶対に必携。
  • sunspot - SOLRによる全文検索エンジン。

このリストは完全ではありません。また、他のgemは今後加えられるかもしれません。リストのgemはすべてフィールドテストされています。これらすべては活発な開発およびコミュニティ活動をしており、よいコード品質であることが知られています。

欠陥のgem

これは問題があるか、他のgemによって取って代わられるgemのリストです。プロジェクトの中でこれらを使用しないようにするべきです。

  • rmagick - このgemはメモリ消費で悪名高い。代わりに minimagick を使用してください。
  • autotest - テストを自動的に実行するための古いソリューションです。 guardwatchr よりも遥かに劣っています。
  • rcov - コードカバレッジツールです。Ruby 1.9と互換性がありません。SimpleCov を使用してください。
  • therubyracer - 非常に大量のメモリを使用するので、本番環境でのこのgemの使用には強く反対します。node.jsの利用を提案します。

このリストは作成途中です。他にもポピュラーであるが欠陥のあるgemを知っていれば教えてください。

プロセス管理

Railsアプリケーションのテスト

新しい機能を実装するためのの最良のアプローチは、おそらくBDDアプローチです。いくつかのハイレベルの機能テスト (一般にCucumberを使用して書かれる) を書くことにより開始します。そして、機能の実装を洗い出すためにこれらのテストを使用します。始めに機能用のビューのspecを書き、適切なビューを作成するためにそれらのspecを使用します。後でビューにデータを与えて、コントローラを実装するために、それらのspecを使用するコントローラ用のspecを作成します。最後に、モデルspecおよびモデル自身を実装します。

Cucumber

このフォーマットは最も一般的なものですが、必須ではありません、ナラティブはフィーチャの複雑さに応じて自由なテキストになりえます。

  • シナリオのDRYを維持するために、シナリオアウトラインを自由に使用してください。

    Scenario Outline: User cannot register with invalid e-mail
      When I try to register with an email "<email>"
      Then I should see the error message "<error>"
    
    Examples:
      |email         |error                 |
      |              |The e-mail is required|
      |invalid email |is not a valid e-mail |
  • シナリオ用のステップはstep_definitionsディレクトリの下の.rbファイルにあります。ステップファイルのファイル名命名規則は[description]_steps.rbです。ステップは異なる基準に基づいた異なるファイルへ分けることができます。各フィーチャ (home_page_steps.rb) のために1ステップのファイルを持つことは可能です。また、特定のオブジェクト(articles_steps.rb) のためにすべてのフィーチャの1ステップのファイルがさらにある場合もあります。

  • 繰り返しを回避するために複数行ステップ引数を使用してください。

    Scenario: User profile
      Given I am logged in as a user "John Doe" with an e-mail "user@test.com"
      When I go to my profile
      Then I should see the following information:
        |First name|John         |
        |Last name |Doe          |
        |E-mail    |user@test.com|
    
    # the step:
    Then /^I should see the following information:$/ do |table|
      table.raw.each do |field, value|
        find_field(field).value.should =~ /#{value}/
      end
    end

RSpec

ビュー

  • ビューのspecspec/viewsのディレクトリ構造は、app/viewsの中のものと一致します。 例えば、app/views/usersの中のspecはspec/views/usersに置かれます。

  • ビューのspecの命名規則はビューの名前に_spec.rbを視界名に加えたものです。例えば、ビュー_form.html.hamlには対応するspec_form.html.haml_spec.rbがあります。

  • spec_helper.rbは各ビューspecファイルの中で要求されるために必要です。

  • 外側のdescribeブロックには、app/viewsなしのビューへのパスを使用します。引数なしで呼ばれた場合、renderメソッドによって使用されます。

    # spec/views/articles/new.html.haml_spec.rb
    require 'spec_helper'
    
    describe 'articles/new.html.haml' do
      # ...
    end
  • ビューspec中では常にモデルをモックしてください。ビューの目的は情報を単に表示することだけです。

  • assignメソッドは、コントローラーによって供給されビューが使用する変数を供給します。

    # spec/views/articles/edit.html.haml_spec.rb
    describe 'articles/edit.html.haml' do
    it 'renders the form for a new article creation' do
      assign(
        :article,
        mock_model(Article).as_new_record.as_null_object
      )
      render
      rendered.should have_selector('form',
        method: 'post',
        action: articles_path
      ) do |form|
        form.should have_selector('input', type: 'submit')
      end
    end
  • should_not肯定よりもCapybaraの否定セレクタを使ってください。

    # 悪い
    page.should_not have_selector('input', type: 'submit')
    page.should_not have_xpath('tr')
    
    # 良い
    page.should have_no_selector('input', type: 'submit')
    page.should have_no_xpath('tr')
  • ビューがヘルパーメソッドを使用する場合、これらのメソッドをスタブする必要があります。ヘルパーメソッドのスタブはtemplateオブジェクト上で行われます。

    # app/helpers/articles_helper.rb
    class ArticlesHelper
      def formatted_date(date)
        # ...
      end
    end
    
    # app/views/articles/show.html.haml
    = "Published at: #{formatted_date(@article.published_at)}"
    
    # spec/views/articles/show.html.haml_spec.rb
    describe 'articles/show.html.haml' do
      it 'displays the formatted date of article publishing' do
        article = mock_model(Article, published_at: Date.new(2012, 01, 01))
        assign(:article, article)
    
        template.stub(:formatted_date).with(article.published_at).and_return('01.01.2012')
    
        render
        rendered.should have_content('Published at: 01.01.2012')
      end
    end
  • ヘルパーのspecはビューspecから分けられ、spec/helpersディレクトリに置かれます。

コントローラ

  • モデルをモックしてメソッドをスタブしてください。コントローラーのテストはモデル生成に左右されるべきではありません。

  • コントローラーが責任を負うべき振る舞いだけをテストしてください:

    • 特別なメソッドを実行してください。

    • アクションから返されたデータ - assigns、など

    • アクションからの結果 - template、render、redirect、など

      ```Ruby
      # Example of a commonly used controller spec
      # spec/controllers/articles_controller_spec.rb
      # We are interested only in the actions the controller should perform
      # So we are mocking the model creation and stubbing its methods
      # And we concentrate only on the things the controller should do
      
      describe ArticlesController do
        # The model will be used in the specs for all methods of the controller
        let(:article) { mock_model(Article) }
      
        describe 'POST create' do
          before { Article.stub(:new).and_return(article) }
      
          it 'creates a new article with the given attributes' do
            Article.should_receive(:new).with(title: 'The New Article Title').and_return(article)
            post :create, message: { title: 'The New Article Title' }
          end
      
          it 'saves the article' do
            article.should_receive(:save)
            post :create
          end
      
          it 'redirects to the Articles index' do
            article.stub(:save)
            post :create
            response.should redirect_to(action: 'index')
          end
        end
      end
      ```
      
  • アクションが受信パラメータに応じて異なる振る舞いをする場合、contextを使用してください。

    # A classic example for use of contexts in a controller spec is creation or update when the object saves successfully or not.
    
    describe ArticlesController do
      let(:article) { mock_model(Article) }
    
      describe 'POST create' do
        before { Article.stub(:new).and_return(article) }
    
        it 'creates a new article with the given attributes' do
          Article.should_receive(:new).with(title: 'The New Article Title').and_return(article)
          post :create, article: { title: 'The New Article Title' }
        end
    
        it 'saves the article' do
          article.should_receive(:save)
          post :create
        end
    
        context 'when the article saves successfully' do
          before { article.stub(:save).and_return(true) }
    
          it 'sets a flash[:notice] message' do
            post :create
            flash[:notice].should eq('The article was saved successfully.')
          end
    
          it 'redirects to the Articles index' do
            post :create
            response.should redirect_to(action: 'index')
          end
        end
    
        context 'when the article fails to save' do
          before { article.stub(:save).and_return(false) }
    
          it 'assigns @article' do
            post :create
            assigns[:article].should be_eql(article)
          end
    
          it 're-renders the "new" template' do
            post :create
            response.should render_template('new')
          end
        end
      end
    end

モデル

  • specではモデルをモックしないでください。

  • 本物のオブジェクトを作るためにfabricationを使用してください。

  • 他のモデルや子オブジェクトをモックすることは容認できます。

  • 重複を避けるために、specにすべてのexampleのためのモデルを作成してください。

    describe Article do
      let(:article) { Fabricate(:article) }
    end
  • 作ったモデルが有効であることを保証するexampleを加えてください。

    describe Article do
      it 'is valid with valid attributes' do
        article.should be_valid
      end
    end
  • バリデーションをテストする場合、検証する必要がある属性を指定するにはhave(x).errors_onを使用してください。be_validの使用は、問題が意図した属性にあることを保証するものではありません。

    # 悪い
    describe '#title' do
      it 'is required' do
        article.title = nil
        article.should_not be_valid
      end
    end
    
    # 好ましい
    describe '#title' do
      it 'is required' do
        article.title = nil
        article.should have(1).error_on(:title)
      end
    end
  • バリデーションされる各属性ごとに個別のdescribeを追加してください。

    describe Article do
      describe '#title' do
        it 'is required' do
          article.title = nil
          article.should have(1).error_on(:title)
        end
      end
    end
  • モデル属性の一意性をテストするときは、他方のオブジェクトにanother_objectという名前を付けてください。

    describe Article
      describe '#title'
        it 'is unique' do
          another_article = Fabricate.build(:article, title: article.title)
          article.should have(1).error_on(:title)
        end
      end
    end

Mailer

Mailer specの中のモデルはモックされるべきです。Mailerはモデル生成に依存するべきではありません。

  • Mailer specは以下のことを確認する必要があります:
    • 見出しが正しい。

    • 送信者のE-mailアドレスが正しい。

    • 受信者のE-mailアドレスが正しく記載されている。

    • メールには必要な情報が含まれている。

      describe SubscriberMailer do
        let(:subscriber) { mock_model(Subscription, email: 'johndoe@test.com', name: 'John Doe') }
      
        describe 'successful registration email' do
          subject { SubscriptionMailer.successful_registration_email(subscriber) }
      
          its(:subject) { should == 'Successful Registration!' }
          its(:from) { should == ['info@your_site.com'] }
          its(:to) { should == [subscriber.email] }
      
          it 'contains the subscriber name' do
            subject.body.encoded.should match(subscriber.name)
          end
        end
      end

アップローダー

  • アップローダーに関してテストすることができるものは、画像が正しくリサイズされるかどうかです。ここでは carrierwave 画像アップローダーのサンプルを示します。

    # rspec/uploaders/person_avatar_uploader_spec.rb
    require 'spec_helper'
    require 'carrierwave/test/matchers'
    
    describe PersonAvatarUploader do
      include CarrierWave::Test::Matchers
    
      # Enable images processing before executing the examples
      before(:all) do
        UserAvatarUploader.enable_processing = true
      end
    
      # Create a new uploader. The model is mocked as the uploading and resizing images does not depend on the model creation.
      before(:each) do
        @uploader = PersonAvatarUploader.new(mock_model(Person).as_null_object)
        @uploader.store!(File.open(path_to_file))
      end
    
      # Disable images processing after executing the examples
      after(:all) do
        UserAvatarUploader.enable_processing = false
      end
    
      # Testing whether image is no larger than given dimensions
      context 'the default version' do
        it 'scales down an image to be no larger than 256 by 256 pixels' do
          @uploader.should be_no_larger_than(256, 256)
        end
      end
    
      # Testing whether image has the exact dimensions
      context 'the thumb version' do
        it 'scales down an image to be exactly 64 by 64 pixels' do
          @uploader.thumb.should have_dimensions(64, 64)
        end
      end
    end
    

参考文献

Railsのスタイルには優れたリソースがあります。時間があるなら検討してみてください。

貢献

このガイドの中で書かれた何も石の中でセットされていません。これはRailsコーディングスタイルに興味を持っている皆と一緒に働きたいという私の願望です。だから私たちはRubyコミュニティ全体に有益となるリソースを作成することができました。

改善のためにチケットやPull Requestを自由に送ってください。あなたの助力に感謝します!

ライセンス

Creative Commons License This work is licensed under a Creative Commons Attribution 3.0 Unported License

Spread the Word

コミュニティー駆動のスタイルガイドは、その存在を知らないコミュニティーにほとんど役に立ちません。ガイドに関してツイートして、友達や同僚と共有してください。私たちが得るすべてのコメントや提案、意見はガイドをわずかにより良くします。そして私たちはできるだけ最良のガイドを持ちたいですよね。

乾杯!
Bozhidar

You can’t perform that action at this time.