└── 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`ステップ定義を使わないでくださいその使い方は、適切にアプリケーションのドメインを反映しない冗長なシナリオの作成につながります。
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 | 
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 |
--------------------------------------------------------------------------------