Getting Started with Rails(ver4.2)の日本語訳 その2

# 原文
http://guides.rubyonrails.org/getting_started.html

## 前のやつ
http://qiita.com/milu0_0_0/items/d67baf569d52cbce1b73

# 6 ２つ目のモデルを追加しよう
それでは次はアプリケーションに２つ目のモデルを定義しましょう。２つ目のモデルは記事に対するコメントを扱います。

## 6.1 モデルを作成しよう
以前記事モデルを作成したのと同じ方法で行います。
ここでは記事へのコメントを保持するCommentモデルを作成します。
次のコマンドをターミナルで実行しましょう

```bash
$ bin/rails generate model Comment commenter:string body:text article:references
```

このコマンドを実行すると次のファイルが生成されます

| File | 目的 |
|--------|--------|
| db/migrate/YYYYMMDDHHMMSS_create_comment.rb | データベースにコメントテーブルを作成するためのファイル |
| app/models/comment.rb| コメントモデル |
| test/models/comment_test.rb | コメントモデルのテストクラス |
| test/fixtures/comments.yml | テストに利用するサンプルコメント(テストデータ) |

まず、app/models/comment.rbを見てみましょう

```ruby
class Comment < ActiveRecord::Base
  belongs_to :article
end
```

これは、以前見た記事モデルととても似ています。
違いはbelongs_to :articleの部分でActiveRecordの関連付けの設定をしています。
関連付けについてはこのガイドの次のセクションで少し学びます。

モデルに加えて、Railsはデータベーステーブルに対応するマイグレーションファイルを作成します。

```ruby
class CreateComments < ActiveRecord::Migration
  def change
    create_table :comments do |t|
      t.string :commenter
      t.text :body
 
      # this line adds an integer column called `article_id`.
      t.references :article, index: true
 
      t.timestamps null: false
    end
  end
end
```

t.referencesの行で２つのモデルの関連性として外部キーを設定しています。
また、インデックスも同時に作成しています。
それではマイグレーションを実行してみましょう

```bash
$ bin/rake db:migrate
```

Railsは現在のデータベースでまだ実行されていないマイグレーションのみを賢く実行します。
今回の場合次のような出力がされるでしょう。

```bash
==  CreateComments: migrating =================================================
-- create_table(:comments)
   -> 0.0115s
==  CreateComments: migrated (0.0119s) ========================================
```

## 6.2 モデルの関連性
ActiveRecordの関連性は２つのモデル間の参照を簡単に宣言することができます。
コメントと記事については次のような関連性を示したいと思います。
- 各コメントは一つの記事に紐づく(Each comment belongs to one article)
- 記事は複数のコメントを持つことが出来る(One article can have many comments)

この２つの文章はRails上で同じ意味を表現するための構文とよく似たものです。
あなたは既にCommentモデルのコードの中でコメントを記事に紐付けているのを見ています。

```ruby
class Comment < ActiveRecord::Base
  belongs_to :article
end
```

更に、app/models/article.rbを編集してもう一つの関連である[記事は複数のコメントを持つことが出来る]を宣言しましょう。

```ruby
class Article < ActiveRecord::Base
  has_many :comments
  validates :title, presence: true,
                    length: { minimum: 5 }
end
```

この２つの定義はActiveRecordの自動で行う機能に良い影響を与えます。
例えば、@articleというインスタンス変数として記事モデルを保持している場合、
@article.commentsとすることで全てのその記事に紐づくコメントを取得することが出来ます。

> 更に詳しいActiveRecordの関連性の情報は、[Active Record Associations](http://guides.rubyonrails.org/association_basics.html)を参照して下さい。

## 6.3 コメントの経路を追加しよう
welcomeコントローラーと同じように、コメントを見るための経路をRailsに追加する必要があります。
config/routes.rbを再度開いて次のように編集しましょう。

```ruby
resources :articles do
  resources :comments
end
```

コメントは記事リソースのネストされたリソースとして作成します。
これは記事とコメントの間の階層関係を表現しています。

> さらに詳しい情報は[Rails Routing](http://guides.rubyonrails.org/getting_started.html)ガイドを参照してください。

## 6.4 コメントのコントローラーを作成しよう
それでは今回必要なコントローラーを以前と同じジェレーターを使って作成しましょう。

```bash
$ bin/rails generate controller Comments
```

これにより５個のファイルと空のディレクトリが作成されます

| File/Directory | 目的 |
|--|--|
|app/controllers/comments_controller.rb|コメントコントローラー
|app/views/comments/| コメントコントローラーに必要なビューをここに格納する
|test/controllers/comments_controller_test.rb| コメントコントローラーのテスト
|app/helpers/comments_helper.rb|ビューヘルパー
|app/assets/javascripts/comment.js.coffee|コントローラー用のCoffeScript
|app/assets/stylesheets/comment.css.scss|コントローラー用のCascading style sheet

多くのブログと同じように、読者に対して記事を読んだ後にそのままコメントを付けれるようにし、
コメントをつけた後、記事画面に戻るようにします。この時記事画面には先ほどつけたコメントが表示されているようにします。
これらの機能をつけるために、CommentsControllerでコメントを作るメソッドと削除するメソッドを作りましょう。
削除はもしスパムコメントが来た場合に利用します。

まずはじめに、記事のページ(app/views/articles/show.html.erb)にコメントをつけるための動線を作りましょう

```erb
<p>
  <strong>Title:</strong>
  <%= @article.title %>
</p>
 
<p>
  <strong>Text:</strong>
  <%= @article.text %>
</p>
 
<h2>Add a comment:</h2>
<%= form_for([@article, @article.comments.build]) do |f| %>
  <p>
    <%= f.label :commenter %><br>
    <%= f.text_field :commenter %>
  </p>
  <p>
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>
 
<%= link_to 'Back', articles_path %> |
<%= link_to 'Edit', edit_article_path(@article) %>
```

ここでは記事の表示ページに新規コメントを追加するフォームを追加しました。
フォームはCommentsControllerのCreateアクションを実行するようになっています。
form_forには配列を渡しており、これによりネステッドな経路(/articles/1/comments)を生成します。

それではapp/controllers/comments_controller.rbにcreateメソッドを作りましょう。

```ruby
class CommentsController < ApplicationController
  def create
    @article = Article.find(params[:article_id])
    @comment = @article.comments.create(comment_params)
    redirect_to article_path(@article)
  end
 
  private
    def comment_params
      params.require(:comment).permit(:commenter, :body)
    end
end
```

ArticleコントローラーのCreateと比べて少しだけ複雑になっています。
なぜならコメントは記事に対してネストされたルートを設定されているからです。
リクエスト毎にそのコメントはどの記事に付けられたのかを追跡できるようにする必要があり、
その為にまず最初にfindメソッドを利用してその記事のArticleモデルを取得しています。

また記事とコメントの関連を利用した便利なメソッドを利用します。
それはコメントを保存するのに利用している、@article.commentsのcreateメソッドです。
これを利用することで追加したコメントは自動的にその記事に属するようになります。

一度コメントを保存した後に、article_path(@article)ヘルパを利用してユーザーに元の記事のページに戻すようにしています。
これについては既に使ったことが有ります。これを実行するとArticleコントローラーのshowアクションが実行され、
そのままshow.html.erbテンプレートがレンダリングされます。
それでは追加されたコメントをユーザーに見えるようにしましょう。
それにはapp/view/articles/show.html.erbに次のように追加しましょう。

```erb
<p>
  <strong>Title:</strong>
  <%= @article.title %>
</p>
 
<p>
  <strong>Text:</strong>
  <%= @article.text %>
</p>
 
<h2>Comments</h2>
<% @article.comments.each do |comment| %>
  <p>
    <strong>Commenter:</strong>
    <%= comment.commenter %>
  </p>
 
  <p>
    <strong>Comment:</strong>
    <%= comment.body %>
  </p>
<% end %>
 
<h2>Add a comment:</h2>
<%= form_for([@article, @article.comments.build]) do |f| %>
  <p>
    <%= f.label :commenter %><br>
    <%= f.text_field :commenter %>
  </p>
  <p>
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>
 
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>
```

これで今すぐにでも記事にコメントを追加し、表示することが出来るようになりました。

![article_with_comments.png](https://qiita-image-store.s3.amazonaws.com/0/44786/b18056de-62c1-ee74-3e75-6785528f7168.png)

# 7 リファクタリング
ここまでで記事とコメント機能がそれぞれ動くようになりました。
ところでapp/views/articles/show.html.erbのテンプレートを開いてみてください。
このテンプレートは非常に長く、厄介なものになってしまいました。
そこでpartialsを利用して綺麗にしていきましょう。

## 7.1 部品のレンダリング
まずはじめに、記事の全てのコメントを表示する部分をpartialを利用して分割しましょう。
新たにapp/views/comments/_comment.html.erbを作成して次の内容で上書きしましょう。

```erb
<p>
  <strong>Commenter:</strong>
  <%= comment.commenter %>
</p>
 
<p>
  <strong>Comment:</strong>
  <%= comment.body %>
</p>
```

次にこれを使うようにapp/views/articles/show.html.erbを次のように変更しましょう

```erb
<p>
  <strong>Title:</strong>
  <%= @article.title %>
</p>
 
<p>
  <strong>Text:</strong>
  <%= @article.text %>
</p>
 
<h2>Comments</h2>
<%= render @article.comments %>
 
<h2>Add a comment:</h2>
<%= form_for([@article, @article.comments.build]) do |f| %>
  <p>
    <%= f.label :commenter %><br>
    <%= f.text_field :commenter %>
  </p>
  <p>
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>
 
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>
```

ここでは@article.commentsコレクションをrenderに渡すことによって、
それぞれのコメントについてapp/views/comments/_comment.html.erbを使ってレンダリングしてくれます。
この時Viewの中ではpartialビューと同じ名前、すなわちcommentという変数に要素が渡されてきます。

## 7.2 フォームもPartialにしよう
次に新規コメント投稿の部分もpartialに移動しましょう。
app/views/comments/_form.html.erbを作成して次の内容で上書きして下さい。

```erb
<%= form_for([@article, @article.comments.build]) do |f| %>
  <p>
    <%= f.label :commenter %><br>
    <%= f.text_field :commenter %>
  </p>
  <p>
    <%= f.label :body %><br>
    <%= f.text_area :body %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>
```

次にapp/views/articles/show.html.erbを次にように修正しましょう。

```erb
<p>
  <strong>Title:</strong>
  <%= @article.title %>
</p>
 
<p>
  <strong>Text:</strong>
  <%= @article.text %>
</p>
 
<h2>Comments</h2>
<%= render @article.comments %>
 
<h2>Add a comment:</h2>
<%= render 'comments/form' %>
 
<%= link_to 'Edit', edit_article_path(@article) %> |
<%= link_to 'Back', articles_path %>
```

このコードの２つ目の`render comments/form`の部分がpartialテンプレートを利用している部分です。
Railsはスラッシュで区切られた文字を適切に解釈しapp/views/commentsディレクトリにある_form.html.erbをレンダリングします。

@articleオブジェクトはインスタンス変数として定義しているので、何れのpartialsでも利用することが出来ます。

#8 コメントを削除する
他の重要な機能としてスパムコメントが投稿された時にそれを削除する機能が必要です。
いくつかのソートを変更するリンクやdestroyアクションをCommentsControllerに実装する必要があります。

まずはじめに、app/views/comments/_comment.html.erbに削除リンクを追加しましょう

```erb
<p>
  <strong>Commenter:</strong>
  <%= comment.commenter %>
</p>
 
<p>
  <strong>Comment:</strong>
  <%= comment.body %>
</p>
 
<p>
  <%= link_to 'Destroy Comment', [comment.article, comment],
               method: :delete,
               data: { confirm: 'Are you sure?' } %>
</p>
```

新たに追加した”Destroy Comment”をクリックすると、DELETE /articles/:article_id/comments/:idが実行されるようにします。
Commentsコントローラー では該当のコメントを検索し、それを削除します。
それではその機能を備えたdestroyアクションをapp/controllers/comments_controller.rbを追加しましょう。

```ruby
class CommentsController < ApplicationController
  def create
    @article = Article.find(params[:article_id])
    @comment = @article.comments.create(comment_params)
    redirect_to article_path(@article)
  end
 
  def destroy
    @article = Article.find(params[:article_id])
    @comment = @article.comments.find(params[:id])
    @comment.destroy
    redirect_to article_path(@article)
  end
 
  private
    def comment_params
      params.require(:comment).permit(:commenter, :body)
    end
end
```

destroyアクションはまず私達が見ている記事を探します。
次にその記事からコメントのコレクション(@article.comments)を取得し、
指定されたコメントを取得・削除し、元の記事画面(記事のshowアクション)にリダイレクトします。

## 8.1 関連オブジェクトの削除
もし貴方が記事を削除する場合、それに紐づくコメントの削除も行う必要があります。
削除を行わなければただ無意味なデータがデータベースを肥大化させていってしまいます。
Railsではこの問題を解消するためにdependent optionを利用することが出来ます。
これを利用するようにArticleモデル(app/models/article.rb)を修正してみましょう。

```ruby
class Article < ActiveRecord::Base
  has_many :comments, dependent: :destroy
  validates :title, presence: true,
                    length: { minimum: 5 }
end
```

#9 セキュリティ
## 9.1 ベーシック認証
もし貴方がブログをインターネット上で公開すると、誰でも記事の投稿や編集、コメントの削除などが行えてしまいます。

Railsではこの場合にうまく使えるシンプルなHTTP認証システムを提供しています。

Articlesコントローラーでは認証を行っていないユーザーの様々なアクションの実行を制限する必要が有ります。
これにはRailsのhttp_basic_authenticate_withメソッドを利用し、
そのメソッドで許可されていればリクエストされたActionを実行するようにします。

認証システムを利用するには、Articlesコントローラー(app/controllers/articles_controller.rb)の一番上で指定します。
今回はindexとshowを除いてユーザーに認証を求めるように指定するので、次のようになります。

```ruby
class ArticlesController < ApplicationController
 
  http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show]
 
  def index
    @articles = Article.all
  end
 
  # 以下は省略
```

また、認証されたユーザーのみがコメントの削除を行えるようにしたいので、Commentコントローラー(app/controllers/comments_controller.rb)も修正しましょう。

```ruby
class CommentsController < ApplicationController
 
  http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy
 
  def create
    @article = Article.find(params[:article_id])
    # ...
  end
 
  # 以下は省略
```

これで記事の新規作成を行うときにHTTP認証が行われるようになりました

![challenge.png](https://qiita-image-store.s3.amazonaws.com/0/44786/cb8122c6-2cb2-36c7-dc8b-984d74386c25.png)

Railsではこれ以外の認証方法も利用することが出来ます。
人気の有る認証用のアドオンとして[Devise](https://github.com/plataformatec/devise)と[Authlogic](https://github.com/binarylogic/authlogic)が有ります。またそれ以外にも多くのアドオンがあります。

##9.2 その他のセキュリティの懸念事項
セキュリティは特にWebアプリケーションにおいて広く深い領域です。
これについて更に掘り下げたドキュメントとして[Ruby on Rails Security Guide](http://guides.rubyonrails.org/security.html)が有りますのでそちらを参照して下さい。

# 10 次の一歩
ここまでであなたは最初のRailsアプリケーションを作成してきました。
あなたはこれを自由に更新して実験し、学習していってください。
しかし、全てを自分でヘルプを借りずに全てを行う必要はありません。
もし必要があれば例えば次のようなサポートやリソースが有りますので活用してみてください
- The[ Ruby on Rails Guides](http://guides.rubyonrails.org/index.html)
- The [Ruby on Rails Tutorial](http://railstutorial.org/book)
- The [Ruby on Rails mailing list](http://groups.google.com/group/rubyonrails-talk)
- The [#rubyonrails](irc://irc.freenode.net/#rubyonrails) channel on irc.freenode.net

また、Railsにはrakeで生成する組み込みのヘルプが含まれています。
- `rake doc:guides`を実行すると完全なRailsGuidesがアプリケーションのdoc/guidesに生成されます。doc/guides/index.htmlをブラウザで開いて見てみて下さい。
- `rake doc:rails`を実行するとRailsのAPIドキュメントがアプリケーションのdoc/apiに生成されます。同じくdoc/api/index.htmlを開いてAPIドキュメントを見ることが出来ます。

> doc:guidesを利用してRailsGuidesをローカルに生成するにはRedClothとNokogiriのGemがそれぞれインストールされている必要があります。
> これらの追加を行うにはGemfileに追加しbundle installを実行して下さい。

#11 設定の落とし穴
Railsを最も簡単に動作させるには、全てのデータをUTF-8で扱うことです。
もしそれが出来ない場合、RailsはUTF-８へデータの変換を行います。しかしこの変換は確実に全て成功するものではありません。
可能な限り全てのデータがUTF-8で渡ってくることを徹底したほうがよいでしょう。

もし、この部分でミスがあった場合、最も一般的な症状は黒いダイアモンドに？が重なった文字がブラウザに表示されることです。
それ以外のでは「Ã¼」や「ü」といった文字が出てくることもあります。
Railsはこういったよくある問題を軽減するために自動的に検知して対応を行います。
しかしUTF-8として送られていない外部データがある場合、自動的に対応が出来ずこのような問題が起きてしまう場合があります。

よくあるUTF-8ではないデータが生成されてしまう状況を２つあげます
- １つ目はあなたのテキストエディタの設定です。
多くのテキストエディタ(例えばTextMate)は標準でUTF-8を利用します。もしあなたのテキストエディタがそうなっていない場合、例えばあなたのViewに「é」を書くと先ほどの黒のダイアモンドに？が重なったものがブラウザに表示されるでしょう。
またテンプレート以外にもあなたのi18nのファイルにも同じことが言えます。UTF-8がデフォルトで無いエディタ(例えばDreamweaver)でもUTF-8に変更を行う方法を提供していますのでそれを利用して下さい。
- ２つ目はデータベースです。
Railsはデフォルトの動作でデータベースとデータをやり取りする際にはUTF-8に変換を行います。
しかしもしデータベースがUTF-8でない場合は、ユーザーから入力された文字に幾つかが欠落してしまう場合があります。
例えばデータベースではLatin-1を内部的に利用してユーザーがロシア語やヘブライ語や日本語を入力した場合です。
可能な場合はデータベースの内部ストレージをUTF-8として利用することをおすすめします。

# 訳してみて・・・
とりあえず走りきった。。。。序盤を見返すとかなり酷いので、いろんなドキュメント読みながら訳してちょっとずつまともな訳文が書けるようになっていければなぁと思います。