└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # 序曲 2 | 3 | > 役割モデルが重要なのだ。
4 | > -- アレックス・マーフィー巡査 / ロボコップ 5 | 6 | このガイドのゴールは、Ruby on Rails 3と4開発のための1セットのベストプラクティスおよびスタイル規則を示すことです。これは、コミュニティー駆動ですでに存在する [Ruby coding style guide](https://github.com/bbatsov/ruby-style-guide) の補足的なガイドです。 7 | 8 | ガイドの中では「[Railsアプリケーションのテスト](#testing-rails-applications)」は「[Railsアプリケーション開発](#developing-rails-applications)」の後にあります。私は、[振る舞い駆動開発 (BDD)](http://en.wikipedia.org/wiki/Behavior_Driven_Development) がソフトウェアを開発する最良の方法であると本当に信じています。それを覚えておいてください。 9 | 10 | Railsは信念の強いフレームワークです。そしてこれは信念の強いガイドです。心の中では、[RSpec](https://www.relishapp.com/rspec)がTest::Unitより優れていると完全に確信しています。[Sass](http://sass-lang.com/)はCSSより優れています。そして、[Haml](http://haml-lang.com/) ([Slim](http://slim-lang.com/))はErbより優れています。したがって、Test::Unit、CSS、Erbに関するどんな助言も、この中で見つけることは期待できません。 11 | 12 | ここにある助言うちのいくつかは、Rails 3.1以上でのみ適用できます。 13 | 14 | [Transmuter](https://github.com/TechnoGate/transmuter)を使用して、PDFあるいはこのガイドのHTMLコピーを生成することができます。 15 | 16 | このガイドには次の言語の翻訳版があります。 17 | 18 | * [中国語簡体字](https://github.com/JuanitoFatas/rails-style-guide/blob/master/README-zhCN.md) 19 | * [中国語繁体字](https://github.com/JuanitoFatas/rails-style-guide/blob/master/README-zhTW.md) 20 | 21 | # 目次 22 | 23 | * [Railsアプリケーション開発](#developing-rails-applications) 24 | * [設定](#configuration) 25 | * [ルーティング](#routing) 26 | * [コントローラ](#controllers) 27 | * [モデル](#models) 28 | * [マイグレーション](#migrations) 29 | * [ビュー](#views) 30 | * [国際化](#internationalization) 31 | * [アセット](#assets) 32 | * [Mailer](#mailers) 33 | * [Bundler](#bundler) 34 | * [有用なgem](#priceless-gems) 35 | * [欠陥のgem](#flawed-gems) 36 | * [プロセス管理](#managing-processes) 37 | * [Railsアプリケーションのテスト](#testing-rails-applications) 38 | * [Cucumber](#cucumber) 39 | * [RSpec](#rspec) 40 | 41 | # Railsアプリケーション開発 42 | 43 | ## 設定 44 | 45 | * `config/initializers`にカスタム初期化コードを入れてください。initializersの中のコードはアプリケーション起動時に実行されます。 46 | * 各gemの初期化コードは、gemと同じ名前の個別のファイルを維持してください。例えば、`carrierwave.rb`、`active_admin.rb`などです。 47 | * development、test、productionの各環境の設定 (`config/environments/`の下の対応するファイル) に従って調節します。 48 | * (もしあれば) プリコンパイルの追加アセットを記します。 49 | 50 | ```Ruby 51 | # config/environments/production.rb 52 | # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) 53 | config.assets.precompile += %w( rails_admin/rails_admin.css rails_admin/rails_admin.js ) 54 | ``` 55 | 56 | * `config/application.rb` では、すべての環境に適用可能な設定をしてください。 57 | * `production`環境に似た、`staging`環境を追加で作成してください。 58 | 59 | ## ルーティング 60 | 61 | * RESTfulリソース (本当に必要ですか?) に対して、さらにアクションを追加する必要がある場合、`member`および`collection`ルートを使用します。 62 | 63 | ```Ruby 64 | # 悪い 65 | get 'subscriptions/:id/unsubscribe' 66 | resources :subscriptions 67 | 68 | # 良い 69 | resources :subscriptions do 70 | get 'unsubscribe', on: :member 71 | end 72 | 73 | # 悪い 74 | get 'photos/search' 75 | resources :photos 76 | 77 | # 良い 78 | resources :photos do 79 | get 'search', on: :collection 80 | end 81 | ``` 82 | 83 | * 複数の`member/collection`ルートを定義する必要がある場合は、代替ブロック・シンタックスを使用します。 84 | 85 | ```Ruby 86 | resources :subscriptions do 87 | member do 88 | get 'unsubscribe' 89 | # more routes 90 | end 91 | end 92 | 93 | resources :photos do 94 | collection do 95 | get 'search' 96 | # more routes 97 | end 98 | end 99 | ``` 100 | 101 | * ActiveRecordモデルの関係をよりよく表現するために、入れ子のルートを使用してください。 102 | 103 | ```Ruby 104 | class Post < ActiveRecord::Base 105 | has_many :comments 106 | end 107 | 108 | class Comments < ActiveRecord::Base 109 | belongs_to :post 110 | end 111 | 112 | # routes.rb 113 | resources :posts do 114 | resources :comments 115 | end 116 | ``` 117 | 118 | * 関連するアクションをグループ化するためにnamespaceを使用してください。 119 | 120 | ```Ruby 121 | namespace :admin do 122 | # Directs /admin/products/* to Admin::ProductsController 123 | # (app/controllers/admin/products_controller.rb) 124 | resources :products 125 | end 126 | ``` 127 | 128 | * 古い記法のワイルド・コントローラ・ルートを使用しないでください。このルートはGETリクエストによってアクセス可能なすべてのコントローラの中ですべてのアクションを生成します。 129 | 130 | ```Ruby 131 | # とても悪い 132 | match ':controller(/:action(/:id(.:format)))' 133 | ``` 134 | 135 | * どのようなルート定義でも`match`を使用しないでください。これはRails 4で廃止されました。 136 | 137 | ## コントローラ 138 | 139 | * コントローラは皮だけの状態を保ってください。これらは単にビュー層のためのデータを取り出すだけのものであるべきであり、ビジネスロジックを含むべきではありません。(すべてのビジネスロジックは、当然モデルに存在するべきです) 140 | * それぞれのコントローラー・アクションは、初期のfindとnew以外、(理想的には) 1つのメソッドだけを起動するべきです。 141 | * コントローラーとビューの間の変数の共有は、2つを超えない範囲にしてください。 142 | 143 | ## モデル 144 | 145 | * 非ActiveRecordモデルのクラスは自由に導入してください。 146 | * モデルには、略語のない意味のある (しかし短い) 名前を付けてください。 147 | * ActiveRecordのバリデーションのような振る舞いをサポートするモデルオブジェクトが必要な場合は、[ActiveAttr](https://github.com/cgriego/active_attr) gemを使用してください。 148 | 149 | ```Ruby 150 | class Message 151 | include ActiveAttr::Model 152 | 153 | attribute :name 154 | attribute :email 155 | attribute :content 156 | attribute :priority 157 | 158 | attr_accessible :name, :email, :content 159 | 160 | validates :name, presence: true 161 | validates :email, format: { with: /\A[-a-z0-9_+\.]+\@([-a-z0-9]+\.)+[a-z0-9]{2,4}\z/i } 162 | validates :content, length: { maximum: 500 } 163 | end 164 | ``` 165 | 166 | より完全な例は [RailsCast on the subject](http://railscasts.com/episodes/326-activeattr) を参照してください。 167 | 168 | ### ActiveRecord 169 | 170 | * 非常に十分な理由 (あなたの管理下にないデータベースを使用する場合など) がない限りは、ActiveRecordデフォルト (テーブル名、主キーなど) を変更しないようにしてください。 171 | 172 | ```Ruby 173 | # 悪い - スキーマを修正できるのなら、このようにしないでください。 174 | class Transaction < ActiveRecord::Base 175 | self.table_name = 'order' 176 | ... 177 | end 178 | ``` 179 | 180 | * マクロスタイルのメソッド (`has_many`, `validates`, など) はクラス定義の始めにまとめてください。 181 | 182 | ```Ruby 183 | class User < ActiveRecord::Base 184 | # デフォルトスコープは最初に(あれば) 185 | default_scope { where(active: true) } 186 | 187 | # 続いて定数 188 | GENDERS = %w(male female) 189 | 190 | # その後attr関係のマクロを置きます 191 | attr_accessor :formatted_date_of_birth 192 | 193 | attr_accessible :login, :first_name, :last_name, :email, :password 194 | 195 | # 関連マクロが続きます 196 | belongs_to :country 197 | 198 | has_many :authentications, dependent: :destroy 199 | 200 | # そしてバリデーションマクロ 201 | validates :email, presence: true 202 | validates :username, presence: true 203 | validates :username, uniqueness: { case_sensitive: false } 204 | validates :username, format: { with: /\A[A-Za-z][A-Za-z0-9._-]{2,19}\z/ } 205 | validates :password, format: { with: /\A\S{8,128}\z/, allow_nil: true} 206 | 207 | # 次にコールバックです 208 | before_save :cook 209 | before_save :update_username_lower 210 | 211 | # その他のマクロ(deviseなど)はコールバックの後に置かれるべきです 212 | 213 | ... 214 | end 215 | ``` 216 | 217 | * `has_and_belongs_to_many`よりも`has_many :through`を好んでください。`has_many :through`を使うことは、結合モデルに対して追加の属性とバリデーションを許可します。 218 | 219 | ```Ruby 220 | # has_and_belongs_to_many を使用 221 | class User < ActiveRecord::Base 222 | has_and_belongs_to_many :groups 223 | end 224 | 225 | class Group < ActiveRecord::Base 226 | has_and_belongs_to_many :users 227 | end 228 | 229 | # 好ましい方法 - has_many :through を使用 230 | class User < ActiveRecord::Base 231 | has_many :memberships 232 | has_many :groups, through: :memberships 233 | end 234 | 235 | class Membership < ActiveRecord::Base 236 | belongs_to :user 237 | belongs_to :group 238 | end 239 | 240 | class Group < ActiveRecord::Base 241 | has_many :memberships 242 | has_many :users, through: :memberships 243 | end 244 | ``` 245 | 246 | * `read_attribute(:attribute)`よりも`self[:attribute]`を好んでください。 247 | 248 | ```Ruby 249 | # 悪い 250 | def amount 251 | read_attribute(:amount) * 100 252 | end 253 | 254 | # 良い 255 | def amount 256 | self[:amount] * 100 257 | end 258 | ``` 259 | 260 | * 常に新しい ["sexy" validations](http://thelucid.com/2010/01/08/sexy-validation-in-edge-rails-rails-3/) を使用してください。 261 | 262 | ```Ruby 263 | # 悪い 264 | validates_presence_of :email 265 | 266 | # 良い 267 | validates :email, presence: true 268 | ``` 269 | 270 | * カスタムバリデーションが2度以上使用されるか、バリデーションが正規表現マッチングである場合は、カスタムバリデータファイルを作成してください。 271 | 272 | ```Ruby 273 | # 悪い 274 | class Person 275 | validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i } 276 | end 277 | 278 | # 良い 279 | class EmailValidator < ActiveModel::EachValidator 280 | def validate_each(record, attribute, value) 281 | record.errors[attribute] << (options[:message] || 'is not a valid email') unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i 282 | end 283 | end 284 | 285 | class Person 286 | validates :email, email: true 287 | end 288 | 289 | * カスタムバリデータは`app/validators`に置いてください。 290 | * あなたが複数の関連するアプリケーションをメンテンスしているか、バリデータが十分に一般的であるならば、共有されるgemへカスタムバリデータを抽出することを検討してください。 291 | * named scopeは自由に使用してください。 292 | 293 | ```Ruby 294 | class User < ActiveRecord::Base 295 | scope :active, -> { where(active: true) } 296 | scope :inactive, -> { where(active: false) } 297 | 298 | scope :with_orders, -> { joins(:orders).select('distinct(users.id)') } 299 | end 300 | ``` 301 | 302 | * 遅延初期化のためにnamed scopeを`lambdas`で包んでください。(Rails 3では単なる処方箋ですが、Rails 4では必須です。) 303 | 304 | ```Ruby 305 | # 悪い 306 | class User < ActiveRecord::Base 307 | scope :active, where(active: true) 308 | scope :inactive, where(active: false) 309 | 310 | scope :with_orders, joins(:orders).select('distinct(users.id)') 311 | end 312 | 313 | # 良い 314 | class User < ActiveRecord::Base 315 | scope :active, -> { where(active: true) } 316 | scope :inactive, -> { where(active: false) } 317 | 318 | scope :with_orders, -> { joins(:orders).select('distinct(users.id)') } 319 | end 320 | ``` 321 | 322 | * ラムダとパラメータを使用したnamed scope定義が複雑になる場合、named scopeと同じ目的のために、代わりに`ActiveRecord::Relation`オブジェクトを返すクラスメソッドを作るのは望ましいことです。恐らくこのようにさらに単純なscopeを定義することができます。 323 | 324 | ```Ruby 325 | class User < ActiveRecord::Base 326 | def self.with_orders 327 | joins(:orders).select('distinct(users.id)') 328 | end 329 | end 330 | ``` 331 | 332 | * `update_attribute`メソッドの振る舞いに用心してください。これはモデルバリデーションを実行せず (`update_attributes`と異なる)、容易にモデルの状態を悪くするかもしれません。このメソッドは最終的にRails 3.2.7で非推奨となり、Rails 4では存在しません。 333 | * ユーザー・フレンドリーなURLを使用してください。URLの中ではモデルの`id`ではなく、モデルの記述的な属性を表示してください。このためのいくつかの方法があります。 334 | * `to_param`メソッドをオーバーライドしてください。これはオブジェクトへのURLを構築するためにRailsによって使用されます。デフォルト実装では、レコードの`id`を文字列として返します。他の「人間が判読可能な」属性を含めるために、これをオーバーライドすることができます。 335 | 336 | ```Ruby 337 | class Person 338 | def to_param 339 | "#{id} #{name}".parameterize 340 | end 341 | end 342 | ``` 343 | URLフレンドリーな値に変換するために、文字列の`parameterize`を呼ぶ必要があります。ActiveRecordの`find`メソッドで見つけることができるように、オブジェクトの`id`が始めにある必要があります。 344 | 345 | * `friendly_id` gemを使用してください。これは、その`id`の代わりにモデルの記述的な属性を使用することによって、人間が判読可能なURLを生成できるようにします。 346 | 347 | ```Ruby 348 | class Person 349 | extend FriendlyId 350 | friendly_id :name, use: :slugged 351 | end 352 | ``` 353 | 354 | 使い方について、より詳細は [gemドキュメント](https://github.com/norman/friendly_id) を確認してください。 355 | 356 | ## マイグレーション 357 | 358 | * `schema.rb` (または`structure.sql`)はバージョン管理下に置いてください。 359 | * 空のデータベースを初期化するために、`rake db:migrate`の代わりに`rake db:schema:load`を使用してください。 360 | * テストデータベースのスキーマをアップデートするには`rake db:test:prepare`を使用してください。 361 | * テーブル自体にデフォルトを設定しないようにしてください。モデル層を代わりに使用してください。 362 | * アプリケーション層での代わりに、マイグレーションでのデフォルト値を強制してください。 363 | 364 | ```Ruby 365 | # 悪い - アプリケーションで強制したデフォルト値 366 | def amount 367 | self[:amount] or 0 368 | end 369 | ``` 370 | 371 | Rails上でのみデフォルトを設定する手法は、多くのRails開発者によって提案されましたが、脆弱にデータを残す多くのアプリケーションのバグに対して非常に脆いアプローチです。 372 |     そのようにRailsのアプリケーションからのデータの整合性を課すことは、ほとんどの普通でないアプリが他のアプリケーションとデータベースを共有することを考慮することは不可能です。 373 | 374 | * 外部キー制約を強制してください。ActiveRecordはネイティブにはサポートしていませんが、[schema_plus](https://github.com/lomba/schema_plus) や [foreigner](https://github.com/matthuhiggins/foreigner)のようないくつかの素晴らしいサードパーティのgemsがあります。 375 | 376 | * 構造変更的なマイグレーションを書くとき (テーブルやカラムの追加など) の、新しいRails 3.1における方法は、 - `up`、`down`メソッドの代わりに、`change`メソッドを使用することです。 377 | 378 | ```Ruby 379 | # 古い方法 380 | class AddNameToPeople < ActiveRecord::Migration 381 | def up 382 | add_column :people, :name, :string 383 | end 384 | 385 | def down 386 | remove_column :people, :name 387 | end 388 | end 389 | 390 | # 好ましい新しい方法 391 | class AddNameToPeople < ActiveRecord::Migration 392 | def change 393 | add_column :people, :name, :string 394 | end 395 | end 396 | ``` 397 | 398 | * マイグレーションではモデルクラスを使用しないでください。モデルクラスは絶えず進化します。将来のマイグレーションのあるポイントで、変更されたモデルを使用したことが原因で停止する場合があります。 399 | 400 | ## ビュー 401 | 402 | * ビューからモデル層を直接呼び出さないでください。 403 | * ビューの中で複雑な体裁出力を作らないでください。ビューヘルパー、またはモデルのメソッドに体裁を出してください。 404 | * 部分テンプレートやレイアウトを使用してコードの重複を軽減させてください。 405 | 406 | ## 国際化 407 | 408 | * 文字列や他のロケール固有の設定は、ビュー、モデル、コントローラで使用するべきではありません。これらのテキストは`config/locales`ディレクトリ内のロケールファイルに移動するべきです。 409 | * ActiveRecordモデルのラベルを翻訳する必要がある場合は、`activerecord`スコープを使用してください: 410 | 411 | ``` 412 | en: 413 | activerecord: 414 | models: 415 | user: Member 416 | attributes: 417 | user: 418 | name: "Full name" 419 | ``` 420 | 421 | `User.model_name.human`は "Member" を返し、`User.human_attribute_name("name")`は "Full name" を返します。これらの属性の翻訳は、ビューのラベルとして使用されます。 422 | 423 | * ActiveRecord属性の翻訳からのビューで使用されるテキストを分離してください。`models`フォルダの中にはモデル、`views`フォルダの中にはビューで使用されるテキスト用のローカルファイルを置いてください。 424 | * 追加ディレクトリからのローカルファイルの編成が完了したということは、これらのディレクトリはロードされるために`application.rb`ファイルで定義されているはずです。 425 | 426 | ```Ruby 427 | # config/application.rb 428 | config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')] 429 | ``` 430 | 431 | * `locales`ディレクトリのルート下のファイルに、日付や通貨の書式のような共有される地域化オプションを置いてください。 432 | * I18nメソッドの短縮形を使用してください。`I18n.translate`の代わりに`I18n.t`。`I18n.localize`の代わりに`I18n.l`です。 433 | * ビューで使われるテキストに "lazy" ルックアップを使用してください。次のような構造です。 434 | 435 | ``` 436 | en: 437 | users: 438 | show: 439 | title: "User details page" 440 | ``` 441 | 442 | `users.show.title`の値は、`app/views/users/show.html.haml`テンプレートで次のように得ることができます。 443 | 444 | ```Ruby 445 | = t '.title' 446 | ``` 447 | 448 | * `:scope`オプションを指定する代わりに、コントローラとモデルをドットで区切ったキーを使用してください。ドットで区切った呼び出しは、読みやすく、階層のトレースがより簡単です。 449 | 450 | ```Ruby 451 | # 方法 452 | I18n.t 'activerecord.errors.messages.record_invalid' 453 | 454 | # 代わりの方法 455 | I18n.t :record_invalid, :scope => [:activerecord, :errors, :messages] 456 | ``` 457 | 458 | * Rails I18nのより詳細な情報は以下で見つけることができます。[Rails Guides](http://guides.rubyonrails.org/i18n.html) 459 | 460 | ## アセット 461 | 462 | アプリケーション内の構成にてこ入れするために[アセットパイプライン](http://guides.rubyonrails.org/asset_pipeline.html)を使用してください。 463 | 464 | * カスタムのstyleshees, javascripts, imagesのために`app/assets`を使用してください。 465 | * あなたが所有するライブラリには`lib/assets`を使用してください。アプリケーションのスコープに入りません。 466 | * [jQuery](http://jquery.com/) や [bootstrap](http://twitter.github.com/bootstrap/) のような第三者のコードは`vendor/assets`に置かれるべきです。 467 | * 可能な場合は、アセットをgem化したバージョンを使用してください。(例:[jquery-rails](https://github.com/rails/jquery-rails), [jquery-ui-rails](https://github.com/joliss/jquery-ui-rails), [bootstrap-sass](https://github.com/thomas-mcdonald/bootstrap-sass), [zurb-foundation](https://github.com/zurb/foundation)). 468 | ) 469 | 470 | ## Mailer 471 | 472 | * Mailerの名前は`SomethingMailer`としてください。接尾辞のないMailerでは、どれがMailerか、どのビューがMailerと関係があるか、明白ではありません。 473 | * HTMLとプレーンテキストの両方のビューテンプレートを提供してください。 474 | * development環境中でメール配信に失敗した際のエラー発生を有効にしてください。エラーはデフォルトでは無効です。 475 | 476 | ```Ruby 477 | # config/environments/development.rb 478 | 479 | config.action_mailer.raise_delivery_errors = true 480 | ``` 481 | 482 | * development環境ではSMTPサーバに`smtp.gmail.com`を使用してください。(もちろん、あなたがローカルSMTPサーバを持っていない場合です) 483 | 484 | * development環境では [Mailcatcher](https://github.com/sj26/mailcatcher) のようなローカルSMTPサーバを使用してください。 485 | 486 | ```Ruby 487 | # config/environments/development.rb 488 | 489 | config.action_mailer.smtp_settings = { 490 | address: 'localhost', 491 | port: 1025, 492 | # more settings 493 | } 494 | ``` 495 | 496 | * ホスト名にデフォルト設定を与えてください。 497 | 498 | ```Ruby 499 | # config/environments/development.rb 500 | config.action_mailer.default_url_options = { host: "#{local_ip}:3000" } 501 | 502 | # config/environments/production.rb 503 | config.action_mailer.default_url_options = { host: 'your_site.com' } 504 | 505 | # in your mailer class 506 | default_url_options[:host] = 'your_site.com' 507 | ``` 508 | 509 | * メールの中でサイトへのリンクを使用する必要がある場合は、`_path`メソッドではなく、常に`_url`を使用してください。`_url`メソッドはホスト名を含んでいますが、`_path`メソッドは含んでいません。 510 | 511 | ```Ruby 512 | # 間違い 513 | You can always find more info about this course 514 | = link_to 'here', url_for(course_path(@course)) 515 | 516 | # 正しい 517 | You can always find more info about this course 518 | = link_to 'here', url_for(course_url(@course)) 519 | ``` 520 | 521 | * FromとToのアドレスに適切な書式を使ってください。次のような書式を使ってください。 522 | 523 | ```Ruby 524 | # in your mailer class 525 | default from: 'Your Name ' 526 | ``` 527 | 528 | * test環境のためのメールdelivery methodには`test`が設定されていることを確認してください。 529 | 530 | ```Ruby 531 | # config/environments/test.rb 532 | 533 | config.action_mailer.delivery_method = :test 534 | ``` 535 | 536 | * developmentとproduction環境のためのメールdelivery methodには`smtp`が設定されていることを確認してください。 537 | 538 | ```Ruby 539 | # config/environments/development.rb, config/environments/production.rb 540 | 541 | config.action_mailer.delivery_method = :smtp 542 | ``` 543 | 544 | * いくつかのメールクライアントが外部スタイルの問題を抱えているため、HTMLメールを送るときは、すべてのスタイルがインラインでなければなりません。しかしながら、これはメンテンナンスを困難にし、コードの重複にもつながります。スタイルを変換し、それを対応するHTMLタグに挿入するための、2つの同じようなgemがあります。[premailer-rails](https://github.com/fphilipe/premailer-rails3) と [roadie](https://github.com/Mange/roadie) です。 545 | * ページレスポンスを生成する間にメールを送ることは避けるべきです。ページの読み込みに遅延が発生しますし、もし複数のメールが送信されるのなら、リクエストがタイムアウトする場合があります。これを克服するためには、[sidekiq](https://github.com/mperham/sidekiq) gemの助けを借りてバックグラウンドプロセスで送信します。 546 | 547 | ## Bundler 548 | 549 | * 開発またはテストのみ使用されるgemは、Gemfileの適切なグループの中に置いてください。 550 | * プロジェクトでは定評のあるgemだけ使用してください。ほとんど知られていないgemを含めることを検討しているのなら、そのソースコードの注意深い調査を最初に行うべきです。 551 | * OS特有のgemは、異なるOSを使用している複数の開発者と一緒のプロジェクトのために、頻繁に変わる`Gemfile.lock`によって得ます。OS Xの特有のgemをすべてGemfileの中の`darwin`グループに、Linux特有のgemを`linux`グループに加えてください。 552 | 553 | ```Ruby 554 | # Gemfile 555 | group :darwin do 556 | gem 'rb-fsevent' 557 | gem 'growl' 558 | end 559 | 560 | group :linux do 561 | gem 'rb-inotify' 562 | end 563 | ``` 564 | 565 | 正しい環境で適切なgemを要求するためには、`config/application.rb`に以下を加えてください。 566 | 567 | ```Ruby 568 | platform = RUBY_PLATFORM.match(/(linux|darwin)/)[0].to_sym 569 | Bundler.require(platform) 570 | ``` 571 | 572 | * バージョン管理から`Gemfile.lock`を取り除かないでください。これは任意に生成されたファイルではありません。- これは`bundle install`した時に、チームメンバーが確実にすべて同じgemバージョンを得るためのものです。 573 | 574 | ## 有用なgem 575 | 576 | 最も重要なプログラミングの法則の1つはこうです。「車輪を再発明するな!」。あるタスクに直面した時には、自分のものを広げる前に、常に既存の解決策を見つけるために周りを見回すべきです。ここにあるリストは、多くのRailsプロジェクトに役立つ「有用な」gemです。(すべてRails 3.1準拠) 577 | 578 | * [active_admin](https://github.com/gregbell/active_admin) - ActiveAdminがあれば、Railsアプリにおける管理者インタフェースの作成は子供の遊びのようなものです。素敵なダッシュボード、CRUD UI、その他いろいろ。とても柔軟でカスタマイズ可能です。 579 | * [better_errors](https://github.com/charliesome/better_errors) - Better ErrorsはRailsのエラーページをより良く有益なページに取り替えます。Rackミドルウェアとして、Railsの外で使用できます。 580 | * [bullet](https://github.com/flyerhzm/bullet) - The Bulletは、アプリケーションが作るクエリの数を減らすことによって、パフォーマンス向上に役立つように設計されています。あなたがアプリケーションを開発している間、一括読み込み(N+1クエリ)をいつ加えなければならないか、また、いつ必要でない一括読み込みを使用するか、いつカウンタキャッシュを使用しなければならないかを通知します。 581 | * [cancan](https://github.com/ryanb/cancan) - CanCanは、リソースへのユーザーのアクセスを制限させることができる認証gemです。べての権限は、単一のファイル(ability.rb)で定義され、アクセス権をチェックし確保するための便利な方法は、アプリケーション全体で利用できます。 582 | * [capybara](https://github.com/jnicklas/capybara) - Capybaraは、Rails、Sinatra、MerbのようなRackアプリケーションにおける統合テストのプロセスを単純化することを目標としています。CapybaraはリアルユーザーのWebアプリケーションとの対話をシミュレートします。それはテストを実行するドライバーに関して不可知論者で、Rack::Testに付属し、Seleniumをビルトインでサポートしています。HtmlUnit、WebKit、env.jsは外部gemによってサポートされます。RSpecとCucmberとのコンビネーションで素晴らしい仕事をします。 583 | * [carrierwave](https://github.com/jnicklas/carrierwave) - Railsにおける究極のファイルアップロードソリューション。アップロードファイルはローカルと、クラウドストレージの両方をサポートします。画像の後処理のためにImageMagickと素晴らしく統合します。 584 | * [compass-rails](https://github.com/chriseppstein/compass) - いくつかのCSSフレームワークのサポートを追加する、素晴らしいgem。CSSファイルのコードが削減され、ブラウザ非互換性との戦いを助けるsaas mixinsのコレクションが含まれています。 585 | * [cucumber-rails](https://github.com/cucumber/cucumber-rails) - Cucumber はRubyで機能テストを開発するプレミアムツールです。cucumber-railsは、RailsへのCucumberの統合を提供します。 586 | * [devise](https://github.com/plataformatec/devise) - Deviseは、Railsアプリケーションのフル機能の認証ソリューションです。 カスタム認証ソリューションを展開するほとんどの場合、Deviseの使用が適しています。 587 | * [fabrication](http://fabricationgem.org/) - 素晴らしいfixtureの代替 (editor's choice). 588 | * [factory_girl](https://github.com/thoughtbot/factory_girl) - fabricationの代わり。とても成熟したfixtureの代替です。fabricationの精神を持っています。 589 | * [ffaker](https://github.com/EmmanuelOga/ffaker) - ダミーデータを生成する手軽なgem。(氏名、住所、その他) 590 | * [feedzirra](https://github.com/pauldix/feedzirra) - とても高速で柔軟なRSS/Atomフィードのパーサー。 591 | * [friendly_id](https://github.com/norman/friendly_id) - モデルのIDの代わりに記述的な属性を使って、人間が読めるURLを生成します 592 | * [globalize](https://github.com/globalize/globalize) - ActiveRecordのモデル/データ変換のためのRails国際化のデファクトスタンダードのライブラリです。Railsのグローバル化とActiveRecordのバージョン4.xを対象としています。これは、Ruby on Railsの新しいI18n APIと互換性があり、ActiveRecordのためのモデルの変換が追加されます。ActiveRecord 3.xのユーザーは、[3-0-stable branch](https://github.com/globalize/globalize/tree/3-0-stable) を確認してください。 593 | * [guard](https://github.com/guard/guard) - ファイルの変更を監視し、それに基づいたタスクを起動する、素晴らしいgemです。多くの有用な拡張が載せられました。自動テストとwatchrよりはるかに優れています。 594 | * [haml-rails](https://github.com/indirect/haml-rails) - haml-railsは、HamlのRailsへの統合を提供します。 595 | * [haml](http://haml-lang.com) - HAMLは簡潔なテンプレート言語で、多くの人に (あなたも含まれます) Erbよりはるかに優れいていると考えられています。 596 | * [kaminari](https://github.com/amatsuda/kaminari) - 素晴らしいページングソリューション。 597 | * [machinist](https://github.com/notahat/machinist) - fixtureは楽しくありません。mechanistなら。 598 | * [rspec-rails](https://github.com/rspec/rspec-rails) - RSpecはTest::MiniTestの代替です。私はRSpecを十分に強く推奨することができません。rspec-railsは、RSpecのRailsへの統合を供給します。 599 | [sidekiq](https://github.com/mperham/sidekiq) - SidekiqはRailsアプリでバックグラウンドジョブを実行するための、おそらく最も簡単で拡張性の高い方法です。 600 | * [simple_form](https://github.com/plataformatec/simple_form) - 一度simple_form (あるいはformtastic) を使用したならば、あなたは決してRailsのデフォルト形式に関して聞かされたくありません。フォームを構築するためにマークアップに対して文句のない素晴らしいDSLを持っています。 601 | * [simplecov-rcov](https://github.com/fguillen/simplecov-rcov) - SimpleCovのためのRCovフォーマッタ。Hudsonのcontininousな統合サーバーとSimpleCovを使用しようとしているなら有用です。 602 | * [simplecov](https://github.com/colszowka/simplecov) - コードカバレッジツール。RCovと異なり、Ruby 1.9と完全に互換性をもちます。素晴らしいレポートを生成します。必携! 603 | * [slim](http://slim-lang.com) - Slimは簡潔なテンプレート言語です。HAMLより優れています (Erbには言及しない)。私が使用するのを止める重くて細いただ1つの理由は、主要なエディタ/IDEのサポートの不足です。そのパフォーマンスは驚異的です。 604 | * [spork](https://github.com/sporkrb/spork) - フレームワーク (現状、RSpec/Cucumber) をテストするためのDRbサーバです。クリーンなテスト状態を保障するために各々の実行前にフォークします。簡単に言えば、多くのテスト環境を事前ロードします。その結果として、テストの最初の時間が大幅に減少します。絶対に必携。 605 | * [sunspot](https://github.com/sunspot/sunspot) - SOLRによる全文検索エンジン。 606 | 607 | このリストは完全ではありません。また、他のgemは今後加えられるかもしれません。リストのgemはすべてフィールドテストされています。これらすべては活発な開発およびコミュニティ活動をしており、よいコード品質であることが知られています。 608 | 609 | ## 欠陥のgem 610 | 611 | これは問題があるか、他のgemによって取って代わられるgemのリストです。プロジェクトの中でこれらを使用しないようにするべきです。 612 | 613 | * [rmagick](http://rmagick.rubyforge.org/) - このgemはメモリ消費で悪名高い。代わりに [minimagick](https://github.com/probablycorey/mini_magick) を使用してください。 614 | * [autotest](http://www.zenspider.com/ZSS/Products/ZenTest/) - テストを自動的に実行するための古いソリューションです。 [guard](https://github.com/guard/guard) と [watchr](https://github.com/mynyml/watchr) よりも遥かに劣っています。 615 | * [rcov](https://github.com/relevance/rcov) - コードカバレッジツールです。Ruby 1.9と互換性がありません。[SimpleCov](https://github.com/colszowka/simplecov) を使用してください。 616 | * [therubyracer](https://github.com/cowboyd/therubyracer) - 非常に大量のメモリを使用するので、本番環境でのこのgemの使用には強く反対します。`node.js`の利用を提案します。 617 | 618 | このリストは作成途中です。他にもポピュラーであるが欠陥のあるgemを知っていれば教えてください。 619 | 620 | ## プロセス管理 621 | 622 | * プロジェクトが様々な外部プロセスに依存している場合は、それらを管理するために [foreman](https://github.com/ddollar/foreman) を使います。 623 | 624 | # Railsアプリケーションのテスト 625 | 626 | 新しい機能を実装するためのの最良のアプローチは、おそらくBDDアプローチです。いくつかのハイレベルの機能テスト (一般にCucumberを使用して書かれる) を書くことにより開始します。そして、機能の実装を洗い出すためにこれらのテストを使用します。始めに機能用のビューのspecを書き、適切なビューを作成するためにそれらのspecを使用します。後でビューにデータを与えて、コントローラを実装するために、それらのspecを使用するコントローラ用のspecを作成します。最後に、モデルspecおよびモデル自身を実装します。 627 | 628 | ## Cucumber 629 | 630 | * 保留中のシナリオに`@wip` (work in progress: 作業中) タグを付けてください。これらのシナリオは無視され、失敗としてマークされません。保留中のシナリオの作業が完了し、テストするための機能性が実装されたら、テストスイートにこのシナリオを含めるために`@wip`タグを削除します。 631 | * `@javascript`タグが付いたシナリオを除外するようにデフォルトのプロフィールをセットアップしてください。それらはテストにブラウザを使用します。通常のシナリオの実行速度を上げるために、それらを無効にすることをお勧めします。 632 | * `@javascript`タグが付けられたシナリオのための別のプロフィールをセットアップしてください。 633 | * プロフィールは`cucumber.yml`ファイルで設定することができます。 634 | 635 | ```Ruby 636 | # definition of a profile: 637 | profile_name: --tags @tag_name 638 | ``` 639 | 640 | * プロフィールは次のコマンドで実行されます。 641 | 642 | ``` 643 | cucumber -p profile_name 644 | ``` 645 | 646 | * fixtureの代わりに [fabrication](http://fabricationgem.org/) 使用している場合は、あらかじめ定義された [fabrication steps](http://fabricationgem.org/#!cucumber-steps) を使用してください。 647 | * 古い`web_steps.rb`ステップ定義を使わないでください![WebステップはCucumberの最新バージョンで削除されています。](http://aslakhellesoy.com/post/11055981222/the-training-wheels-came-off)その使い方は、適切にアプリケーションのドメインを反映しない冗長なシナリオの作成につながります。 648 | * 要素idではなく、可視のテキスト (リンク、ボタンなど) で要素の存在を調べる場合。これは、i18nに関する問題を見つけることができます。 649 | * 同じ種類のオブジェクトの異なる機能のために、個別のフィーチャを作ってください: 650 | 651 | ```Ruby 652 | # 悪い 653 | Feature: Articles 654 | # ... フィーチャ実装 ... 655 | 656 | # 良い 657 | Feature: Article Editing 658 | # ... フィーチャ実装 ... 659 | 660 | Feature: Article Publishing 661 | # ... フィーチャ実装 ... 662 | 663 | Feature: Article Search 664 | # ... フィーチャ実装 ... 665 | 666 | ``` 667 | 668 | * 各々のフィーチャには3つの主成分があります。 669 | * タイトル 670 | * ナラティブ (物語) - フィーチャについての短い説明。 671 | * 合格基準 - 個々のステップから構成されたシナリオのセット。 672 | * 最も一般的なフォーマットがConnextraフォーマットとして知られています。 673 | 674 | ```Ruby 675 | In order to [benefit] ... 676 | A [stakeholder]... 677 | Wants to [feature] ... 678 | ``` 679 | 680 | このフォーマットは最も一般的なものですが、必須ではありません、ナラティブはフィーチャの複雑さに応じて自由なテキストになりえます。 681 | 682 | * シナリオのDRYを維持するために、シナリオアウトラインを自由に使用してください。 683 | 684 | ```Ruby 685 | Scenario Outline: User cannot register with invalid e-mail 686 | When I try to register with an email "" 687 | Then I should see the error message "" 688 | 689 | Examples: 690 | |email |error | 691 | | |The e-mail is required| 692 | |invalid email |is not a valid e-mail | 693 | ``` 694 | 695 | * シナリオ用のステップは`step_definitions`ディレクトリの下の`.rb`ファイルにあります。ステップファイルのファイル名命名規則は`[description]_steps.rb`です。ステップは異なる基準に基づいた異なるファイルへ分けることができます。各フィーチャ (`home_page_steps.rb`) のために1ステップのファイルを持つことは可能です。また、特定のオブジェクト(`articles_steps.rb`) のためにすべてのフィーチャの1ステップのファイルがさらにある場合もあります。 696 | * 繰り返しを回避するために複数行ステップ引数を使用してください。 697 | 698 | ```Ruby 699 | Scenario: User profile 700 | Given I am logged in as a user "John Doe" with an e-mail "user@test.com" 701 | When I go to my profile 702 | Then I should see the following information: 703 | |First name|John | 704 | |Last name |Doe | 705 | |E-mail |user@test.com| 706 | 707 | # the step: 708 | Then /^I should see the following information:$/ do |table| 709 | table.raw.each do |field, value| 710 | find_field(field).value.should =~ /#{value}/ 711 | end 712 | end 713 | ``` 714 | 715 | ## RSpec 716 | 717 | * exampleごとに1つの期待値だけを使用してください。 718 | 719 | ```Ruby 720 | # 悪い 721 | describe ArticlesController do 722 | #... 723 | 724 | describe 'GET new' do 725 | it 'assigns new article and renders the new article template' do 726 | get :new 727 | assigns[:article].should be_a_new Article 728 | response.should render_template :new 729 | end 730 | end 731 | 732 | # ... 733 | end 734 | 735 | # 良い 736 | describe ArticlesController do 737 | #... 738 | 739 | describe 'GET new' do 740 | it 'assigns a new article' do 741 | get :new 742 | assigns[:article].should be_a_new Article 743 | end 744 | 745 | it 'renders the new article template' do 746 | get :new 747 | response.should render_template :new 748 | end 749 | end 750 | 751 | end 752 | ``` 753 | 754 | * `describe`と`context`を多用してください。 755 | * `describe`ブロックの命名は次のようにしてください。 756 | * メソッド以外は "description" とする。 757 | * メソッドには "#method" 「#」を使う。 758 | * クラスメソッドには ".method" 「.」を使う。 759 | 760 | ```Ruby 761 | class Article 762 | def summary 763 | #... 764 | end 765 | 766 | def self.latest 767 | #... 768 | end 769 | end 770 | 771 | # the spec... 772 | describe Article do 773 | describe '#summary' do 774 | #... 775 | end 776 | 777 | describe '.latest' do 778 | #... 779 | end 780 | end 781 | ``` 782 | 783 | * テストオブジェクトの生成には [fabricators](http://fabricationgem.org/) を使用してください。 784 | * モックとスタブを多用してください。 785 | 786 | ```Ruby 787 | # モデルをモック 788 | article = mock_model(Article) 789 | 790 | # メソッドをスタブ 791 | Article.stub(:find).with(article.id).and_return(article) 792 | ``` 793 | 794 | * モデルをモックする場合、`as_null_object`メソッドを使用してください。これは、期待するメッセージにのみをリスニングし、他のメッセージを無視するように出力に命じます。 795 | 796 | ```Ruby 797 | article = mock_model(Article).as_null_object 798 | ``` 799 | 800 | * exampleのためにデータを作る際は、`before(:each)`ブロックの代わりに`let`ブロックを使用してください。 801 | 802 | ```Ruby 803 | # こうしてください 804 | let(:article) { Fabricate(:article) } 805 | 806 | # ... これよりも 807 | before(:each) { @article = Fabricate(:article) } 808 | ``` 809 | 810 | * できれば`subject`を使用してください。 811 | 812 | ```Ruby 813 | describe Article do 814 | subject { Fabricate(:article) } 815 | 816 | it 'is not published on creation' do 817 | subject.should_not be_published 818 | end 819 | end 820 | ``` 821 | 822 | * できれば`specify`を使用してください。これは`it`の同意語ですが、docstringがない場合、より読みやすいです。 823 | 824 | ```Ruby 825 | # 悪い 826 | describe Article do 827 | before { @article = Fabricate(:article) } 828 | 829 | it 'is not published on creation' do 830 | @article.should_not be_published 831 | end 832 | end 833 | 834 | # 良い 835 | describe Article do 836 | let(:article) { Fabricate(:article) } 837 | specify { article.should_not be_published } 838 | end 839 | ``` 840 | 841 | * できれば`its`を使用してください。 842 | 843 | ```Ruby 844 | # 悪い 845 | describe Article do 846 | subject { Fabricate(:article) } 847 | 848 | it 'has the current date as creation date' do 849 | subject.creation_date.should == Date.today 850 | end 851 | end 852 | 853 | # 良い 854 | describe Article do 855 | subject { Fabricate(:article) } 856 | its(:creation_date) { should == Date.today } 857 | end 858 | ``` 859 | 860 | * 他の多くのテストで共有することができるspecグループを作成したい場合は、`shared_examples`を使用してください。 861 | 862 | ```Ruby 863 | # 悪い 864 | describe Array do 865 | subject { Array.new [7, 2, 4] } 866 | 867 | context "initialized with 3 items" do 868 | its(:size) { should eq(3) } 869 | end 870 | end 871 | 872 | describe Set do 873 | subject { Set.new [7, 2, 4] } 874 | 875 | context "initialized with 3 items" do 876 | its(:size) { should eq(3) } 877 | end 878 | end 879 | 880 | # 良い 881 | shared_examples "a collection" do 882 | subject { described_class.new([7, 2, 4]) } 883 | 884 | context "initialized with 3 items" do 885 | its(:size) { should eq(3) } 886 | end 887 | end 888 | 889 | describe Array do 890 | it_behaves_like "a collection" 891 | end 892 | 893 | describe Set do 894 | it_behaves_like "a collection" 895 | end 896 | 897 | ### ビュー 898 | 899 | * ビューのspec`spec/views`のディレクトリ構造は、`app/views`の中のものと一致します。 900 | 例えば、`app/views/users`の中のspecは`spec/views/users`に置かれます。 901 | * ビューのspecの命名規則はビューの名前に`_spec.rb`を視界名に加えたものです。例えば、ビュー`_form.html.haml`には対応するspec`_form.html.haml_spec.rb`があります。 902 | * `spec_helper.rb`は各ビューspecファイルの中で要求されるために必要です。 903 | * 外側の`describe`ブロックには、`app/views`なしのビューへのパスを使用します。引数なしで呼ばれた場合、`render`メソッドによって使用されます。 904 | 905 | ```Ruby 906 | # spec/views/articles/new.html.haml_spec.rb 907 | require 'spec_helper' 908 | 909 | describe 'articles/new.html.haml' do 910 | # ... 911 | end 912 | ``` 913 | 914 | * ビューspec中では常にモデルをモックしてください。ビューの目的は情報を単に表示することだけです。 915 | * `assign`メソッドは、コントローラーによって供給されビューが使用する変数を供給します。 916 | 917 | ```Ruby 918 | # spec/views/articles/edit.html.haml_spec.rb 919 | describe 'articles/edit.html.haml' do 920 | it 'renders the form for a new article creation' do 921 | assign( 922 | :article, 923 | mock_model(Article).as_new_record.as_null_object 924 | ) 925 | render 926 | rendered.should have_selector('form', 927 | method: 'post', 928 | action: articles_path 929 | ) do |form| 930 | form.should have_selector('input', type: 'submit') 931 | end 932 | end 933 | ``` 934 | 935 | * should_not肯定よりもCapybaraの否定セレクタを使ってください。 936 | 937 | ```Ruby 938 | # 悪い 939 | page.should_not have_selector('input', type: 'submit') 940 | page.should_not have_xpath('tr') 941 | 942 | # 良い 943 | page.should have_no_selector('input', type: 'submit') 944 | page.should have_no_xpath('tr') 945 | ``` 946 | 947 | * ビューがヘルパーメソッドを使用する場合、これらのメソッドをスタブする必要があります。ヘルパーメソッドのスタブは`template`オブジェクト上で行われます。 948 | 949 | ```Ruby 950 | # app/helpers/articles_helper.rb 951 | class ArticlesHelper 952 | def formatted_date(date) 953 | # ... 954 | end 955 | end 956 | 957 | # app/views/articles/show.html.haml 958 | = "Published at: #{formatted_date(@article.published_at)}" 959 | 960 | # spec/views/articles/show.html.haml_spec.rb 961 | describe 'articles/show.html.haml' do 962 | it 'displays the formatted date of article publishing' do 963 | article = mock_model(Article, published_at: Date.new(2012, 01, 01)) 964 | assign(:article, article) 965 | 966 | template.stub(:formatted_date).with(article.published_at).and_return('01.01.2012') 967 | 968 | render 969 | rendered.should have_content('Published at: 01.01.2012') 970 | end 971 | end 972 | ``` 973 | 974 | * ヘルパーのspecはビューspecから分けられ、`spec/helpers`ディレクトリに置かれます。 975 | 976 | ### コントローラ 977 | 978 | * モデルをモックしてメソッドをスタブしてください。コントローラーのテストはモデル生成に左右されるべきではありません。 979 | * コントローラーが責任を負うべき振る舞いだけをテストしてください: 980 | * 特別なメソッドを実行してください。 981 | * アクションから返されたデータ - assigns、など 982 | * アクションからの結果 - template、render、redirect、など 983 | 984 | ```Ruby 985 | # Example of a commonly used controller spec 986 | # spec/controllers/articles_controller_spec.rb 987 | # We are interested only in the actions the controller should perform 988 | # So we are mocking the model creation and stubbing its methods 989 | # And we concentrate only on the things the controller should do 990 | 991 | describe ArticlesController do 992 | # The model will be used in the specs for all methods of the controller 993 | let(:article) { mock_model(Article) } 994 | 995 | describe 'POST create' do 996 | before { Article.stub(:new).and_return(article) } 997 | 998 | it 'creates a new article with the given attributes' do 999 | Article.should_receive(:new).with(title: 'The New Article Title').and_return(article) 1000 | post :create, message: { title: 'The New Article Title' } 1001 | end 1002 | 1003 | it 'saves the article' do 1004 | article.should_receive(:save) 1005 | post :create 1006 | end 1007 | 1008 | it 'redirects to the Articles index' do 1009 | article.stub(:save) 1010 | post :create 1011 | response.should redirect_to(action: 'index') 1012 | end 1013 | end 1014 | end 1015 | ``` 1016 | 1017 | * アクションが受信パラメータに応じて異なる振る舞いをする場合、contextを使用してください。 1018 | 1019 | ```Ruby 1020 | # A classic example for use of contexts in a controller spec is creation or update when the object saves successfully or not. 1021 | 1022 | describe ArticlesController do 1023 | let(:article) { mock_model(Article) } 1024 | 1025 | describe 'POST create' do 1026 | before { Article.stub(:new).and_return(article) } 1027 | 1028 | it 'creates a new article with the given attributes' do 1029 | Article.should_receive(:new).with(title: 'The New Article Title').and_return(article) 1030 | post :create, article: { title: 'The New Article Title' } 1031 | end 1032 | 1033 | it 'saves the article' do 1034 | article.should_receive(:save) 1035 | post :create 1036 | end 1037 | 1038 | context 'when the article saves successfully' do 1039 | before { article.stub(:save).and_return(true) } 1040 | 1041 | it 'sets a flash[:notice] message' do 1042 | post :create 1043 | flash[:notice].should eq('The article was saved successfully.') 1044 | end 1045 | 1046 | it 'redirects to the Articles index' do 1047 | post :create 1048 | response.should redirect_to(action: 'index') 1049 | end 1050 | end 1051 | 1052 | context 'when the article fails to save' do 1053 | before { article.stub(:save).and_return(false) } 1054 | 1055 | it 'assigns @article' do 1056 | post :create 1057 | assigns[:article].should be_eql(article) 1058 | end 1059 | 1060 | it 're-renders the "new" template' do 1061 | post :create 1062 | response.should render_template('new') 1063 | end 1064 | end 1065 | end 1066 | end 1067 | ``` 1068 | 1069 | ### モデル 1070 | 1071 | * specではモデルをモックしないでください。 1072 | * 本物のオブジェクトを作るためにfabricationを使用してください。 1073 | * 他のモデルや子オブジェクトをモックすることは容認できます。 1074 | * 重複を避けるために、specにすべてのexampleのためのモデルを作成してください。 1075 | 1076 | ```Ruby 1077 | describe Article do 1078 | let(:article) { Fabricate(:article) } 1079 | end 1080 | ``` 1081 | 1082 | * 作ったモデルが有効であることを保証するexampleを加えてください。 1083 | 1084 | ```Ruby 1085 | describe Article do 1086 | it 'is valid with valid attributes' do 1087 | article.should be_valid 1088 | end 1089 | end 1090 | ``` 1091 | 1092 | * バリデーションをテストする場合、検証する必要がある属性を指定するには`have(x).errors_on`を使用してください。`be_valid`の使用は、問題が意図した属性にあることを保証するものではありません。 1093 | 1094 | ```Ruby 1095 | # 悪い 1096 | describe '#title' do 1097 | it 'is required' do 1098 | article.title = nil 1099 | article.should_not be_valid 1100 | end 1101 | end 1102 | 1103 | # 好ましい 1104 | describe '#title' do 1105 | it 'is required' do 1106 | article.title = nil 1107 | article.should have(1).error_on(:title) 1108 | end 1109 | end 1110 | ``` 1111 | 1112 | * バリデーションされる各属性ごとに個別の`describe`を追加してください。 1113 | 1114 | ```Ruby 1115 | describe Article do 1116 | describe '#title' do 1117 | it 'is required' do 1118 | article.title = nil 1119 | article.should have(1).error_on(:title) 1120 | end 1121 | end 1122 | end 1123 | ``` 1124 | 1125 | * モデル属性の一意性をテストするときは、他方のオブジェクトに`another_object`という名前を付けてください。 1126 | 1127 | ```Ruby 1128 | describe Article 1129 | describe '#title' 1130 | it 'is unique' do 1131 | another_article = Fabricate.build(:article, title: article.title) 1132 | article.should have(1).error_on(:title) 1133 | end 1134 | end 1135 | end 1136 | ``` 1137 | 1138 | ### Mailer 1139 | 1140 | Mailer specの中のモデルはモックされるべきです。Mailerはモデル生成に依存するべきではありません。 1141 | * Mailer specは以下のことを確認する必要があります: 1142 | * 見出しが正しい。 1143 | * 送信者のE-mailアドレスが正しい。 1144 | * 受信者のE-mailアドレスが正しく記載されている。 1145 | * メールには必要な情報が含まれている。 1146 | 1147 | ```Ruby 1148 | describe SubscriberMailer do 1149 | let(:subscriber) { mock_model(Subscription, email: 'johndoe@test.com', name: 'John Doe') } 1150 | 1151 | describe 'successful registration email' do 1152 | subject { SubscriptionMailer.successful_registration_email(subscriber) } 1153 | 1154 | its(:subject) { should == 'Successful Registration!' } 1155 | its(:from) { should == ['info@your_site.com'] } 1156 | its(:to) { should == [subscriber.email] } 1157 | 1158 | it 'contains the subscriber name' do 1159 | subject.body.encoded.should match(subscriber.name) 1160 | end 1161 | end 1162 | end 1163 | ``` 1164 | 1165 | ### アップローダー 1166 | 1167 | * アップローダーに関してテストすることができるものは、画像が正しくリサイズされるかどうかです。ここでは [carrierwave](https://github.com/jnicklas/carrierwave) 画像アップローダーのサンプルを示します。 1168 | 1169 | ```Ruby 1170 | 1171 | # rspec/uploaders/person_avatar_uploader_spec.rb 1172 | require 'spec_helper' 1173 | require 'carrierwave/test/matchers' 1174 | 1175 | describe PersonAvatarUploader do 1176 | include CarrierWave::Test::Matchers 1177 | 1178 | # Enable images processing before executing the examples 1179 | before(:all) do 1180 | UserAvatarUploader.enable_processing = true 1181 | end 1182 | 1183 | # Create a new uploader. The model is mocked as the uploading and resizing images does not depend on the model creation. 1184 | before(:each) do 1185 | @uploader = PersonAvatarUploader.new(mock_model(Person).as_null_object) 1186 | @uploader.store!(File.open(path_to_file)) 1187 | end 1188 | 1189 | # Disable images processing after executing the examples 1190 | after(:all) do 1191 | UserAvatarUploader.enable_processing = false 1192 | end 1193 | 1194 | # Testing whether image is no larger than given dimensions 1195 | context 'the default version' do 1196 | it 'scales down an image to be no larger than 256 by 256 pixels' do 1197 | @uploader.should be_no_larger_than(256, 256) 1198 | end 1199 | end 1200 | 1201 | # Testing whether image has the exact dimensions 1202 | context 'the thumb version' do 1203 | it 'scales down an image to be exactly 64 by 64 pixels' do 1204 | @uploader.thumb.should have_dimensions(64, 64) 1205 | end 1206 | end 1207 | end 1208 | 1209 | ``` 1210 | 1211 | # 参考文献 1212 | 1213 | Railsのスタイルには優れたリソースがあります。時間があるなら検討してみてください。 1214 | 1215 | * [The Rails 3 Way](http://www.amazon.com/Rails-Way-Addison-Wesley-Professional-Ruby/dp/0321601661) 1216 | * [Ruby on Rails Guides](http://guides.rubyonrails.org/) 1217 | * [The RSpec Book](http://pragprog.com/book/achbd/the-rspec-book) 1218 | * [The Cucumber Book](http://pragprog.com/book/hwcuc/the-cucumber-book) 1219 | * [Everyday Rails Testing with RSpec](https://leanpub.com/everydayrailsrspec) 1220 | 1221 | # 貢献 1222 | 1223 | このガイドの中で書かれた何も石の中でセットされていません。これはRailsコーディングスタイルに興味を持っている皆と一緒に働きたいという私の願望です。だから私たちはRubyコミュニティ全体に有益となるリソースを作成することができました。 1224 | 1225 | 改善のためにチケットやPull Requestを自由に送ってください。あなたの助力に感謝します! 1226 | 1227 | # ライセンス 1228 | 1229 | ![Creative Commons License](http://i.creativecommons.org/l/by/3.0/88x31.png) 1230 | This work is licensed under a [Creative Commons Attribution 3.0 Unported License](http://creativecommons.org/licenses/by/3.0/deed.en_US) 1231 | 1232 | # Spread the Word 1233 | 1234 | コミュニティー駆動のスタイルガイドは、その存在を知らないコミュニティーにほとんど役に立ちません。ガイドに関してツイートして、友達や同僚と共有してください。私たちが得るすべてのコメントや提案、意見はガイドをわずかにより良くします。そして私たちはできるだけ最良のガイドを持ちたいですよね。 1235 | 1236 | 乾杯!
1237 | [Bozhidar](https://twitter.com/bbatsov) 1238 | --------------------------------------------------------------------------------