hiyoko-programingの日記

プログラミングを勉強したてのひよっ子。   エンジニア目指して勉強中。

M V Cの実装

投稿画面を作成する

ツイートの新規作成画面を作成し、遷移できるようにする考え方を確認する。ツイートの新規作成画面を表示するためのアクションと新規作成画面があれば、ブラウザからのリクエストによってそのアクションを動かすことで新規作成画面は表示される。どのリクエストによってどのアクションが動くのかを決定するためにルーティングが必要。ここはページを表示するだけの実装で単純なので、実際の処理の順番どおりルーティングから定義する。

ルーティング設定

まずどんなリクエストをしたらどんなアクションが動くかを設定する。ツイートの入力画面は一覧の表示とは別のページを用意するので、以下のようにルーティングを設定する。

 routes.rbを以下のように編集。

config/routes.rb

1
2
3
4
  Rails.application.routes.draw do
    get   'tweets'      =>  'tweets#index'     #ツイート一覧画面
    get   'tweets/new'  =>  'tweets#new'       #ツイート投稿画面
  end

  

routes.rbの3行目では、ルーティングは前半部分がパス、後半部分がコントローラとアクションを示している。
つまり、新たに「get 'tweets/new' => 'tweets#new’」とルーティングを追記したことによって、「localhost:3000/tweets/new」にアクセスした時にtweetsコントローラのnewアクションが動くことを示している。

コントローラに新たなアクションを定義

処理の順番通りいくと、ルーティングの次はコントローラ。ツイートの一覧画面を作成した際は初めてのページ作成だったので、新しくコントローラを作成する必要があったが、今回はすでにtweets_controllerがあるのでその中に新しくアクションを定義する。

 tweets_controller.rbを以下のように編集

app/controlers/tweets_controller.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  class TweetsController < ApplicationController

    def index
      @tweets = Tweet.all
    end

    def new
    end

  end

 

投稿画面ではモデルを利用した情報の表示などは行わないので、単にnewアクションを定義するだけで構わない。

ビューファイル作成

最後に投稿画面のビューファイルを作成する。投稿画面ではツイートの投稿を行う。そのため、単に情報を表示するページではなく、フォームによる情報の送信機能をつける必要がある。

ビューファイルの作成

あるコントローラのアクションに対応するビューは、アプリケーション内のapp/views/コントローラ名/以下に、アクション名.html.erbという名前で作成する。

 「new.html.erb」というファイルを以下のディレクトリに作成する

  •  app
    •  views
      •  tweets
        •  new.html.erb

投稿フォームの実装

ユーザーが情報を入力するためのフォームを作る。

 フォーム

フォームとは、ユーザーが情報を入力し、その情報をサーバーに送信するためのもの。HTMLのコードの中にform要素を作成し、その中にフォームを構成する部品のinput要素やtextarea要素を配置することで作成することができる。

sample.html
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
  <div>
    <form action="/test" method="post">
      <h3>
        サンプルフォーム
      </h3>
      <div>
        <label>Name:</label>
        <input placeholder="Name" type="text" id="name">
      </div>
      <div>
        <label>E-mail:</label>
        <input placeholder="E-mail" type="email" id="mail">
      </div>
      <div>
        <label>Message:</label>
        <textarea placeholder="Message" id="message"></textarea>
      </div>
      <div>
        <input type="submit">
      </div>
    </form>
  </div>

フォーム

 form_tag

ビューにHTMLのformタグを作成することで、ビューから情報を送信できるが、Railsではセキュリティの観点から、HTMLのformタグだけで作成したフォームを使用することは推奨されない。通常、Railsでフォームから情報を送信するためにはform_tagを始めとするヘルパーメソッドを使用する。似たメソッドとしてform_forもあるが、こちらは後ほど。

例1:

sample.html
1
2
3
4
5
6
  <div>
    <form action="/test" method="post">
      <input type="text" id="name">
      <input type="submit">
    </form>
  </div>

例2:

例1のフォームをform_tagを使用して記述したもの

sample.html
1
2
3
4
5
6
  <div>
    <%= form_tag('/test', method: :post) do %>
      <input type="text" id="name">
      <input type="submit">
    <% end %>
  </div>

通常は例1のように記述することでフォームを作成することができる。例2では、例1のフォームをform_tagを使用して記述したもの。action属性は'アクション名'method属性はmethod: :メソッド名と記述することで、同様の記述を行うことができる。また、フォームの場合はフォームの終了時に</form>で囲んでいたが、form_tagの場合は<% end %>で囲む。

app/views/tweets/new.html.erb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<div class="contents row">
  <%= form_tag('/tweets', method: :post) do %>
    <h3>
      投稿する
    </h3>
    <input placeholder="Nickname" type="text" name="name">
    <input placeholder="Image Url" type="text" name="image">
    <textarea cols="30" name="text" placeholder="text" rows="10"></textarea>
    <input type="submit" value="SENT">
  <% end %>
</div>

 

how to copy and paste

 

以上の作業で投稿画面を作成することができたので、実際に確認。

http://localhost:3000/tweets/new

投稿画面

 

要点チェック

 

投稿機能の実装

入力内容に応じてツイートをテーブルに保存できるように編集していく。これまでと同様、ルーティング、コントローラ、ビューを一通り作成していく。

ポイント

1.ユーザーがフォームに入力した情報は、どのようにRails側に送られるのか?
2.Rails側ではどのように情報を受取り、テーブルにレコードとして保存するのか?

こちらの機能については、話をわかりやすくするために、コントローラから編集。

コントローラに新たなアクションを定義

テーブルにレコードを保存するためにはcreateメソッドを利用した。

テーブルにレコードを保存
1
Tweet.create(name: 'abe', image: 'sample.jpeg', text: 'hello')

あるリクエストで動かしたアクションの中にこのコードが入っていれば、ルーティングを設定しリクエストによってそのアクションを動かすことでテーブルにレコードを保存することができそう。アクションを定義する。

Railsでは、「テーブルにレコードを新規作成する」際のアクションはcreateという名前にする。

app/controlers/tweets_controller.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  class TweetsController < ApplicationController

    def index
      @tweets = Tweet.all
    end

    def new
    end

    def create
      Tweet.create(name: "", image: "", text: "")
    end

  end

これで、createアクションが動いた際にtweetsテーブルに新たなレコードが保存される。しかし、引数に渡しているハッシュの値は全て空の文字列になっている。
このままではたとえcreateアクションが動いたとしても、ユーザーがフォームに入力した内容は反映されない。ここをどうするかは、後程説明する。 

ルーティングを設定しよう

次に、createアクションを動かすためのルーティングを設定する。
今回はフォームの「SENT」ボタンを押した際にリクエストが行われるようにするため、まずフォームからパスhttpメソッドを指定する必要がある。

少し前に編集したビューファイルの2行目、form_tag以降の部分に注目。

app/views/tweets/new.html.erb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<div class="contents row">
  <%= form_tag('/tweets', method: :post) do %>
    <h3>
      投稿する
    </h3>
    <input placeholder="Nickname" type="text" name="name">
    <input placeholder="Image Url" type="text" name="image">
    <textarea cols="30" name="text" placeholder="text" rows="10"></textarea>
    <input type="submit" value="SENT">
  <% end %>
</div>

これは、form_tagというメソッドに2つの引数をもたせている状態
form_tagメソッドは引数でどんなリクエストをするかを決めることができる。
はじめの引数を第一引数、次のものを第二引数、などと呼ぶが、第一引数は文字列の/tweets。これは、formの送信ボタンを押した際のリクエストのうち、パスをあらわしている。
第二引数はハッシュクラスのインスタンスmethod: :post。同じくリクエストについて示していて、こちらはhttpメソッドをpostにするという書き方。
まとめると、/tweetspostメソッドでフォームに入力された情報を送信することを示している。

 HTTPメソッド

ウェブサイトを閲覧する際にPCからサーバーにリクエストが送られ、それに対してサーバーからレスポンスが返ってくるが、このリクエストはその目的によっていくつかの種類(メソッドといいます)に分けられる。

HTTPメソッド  役割
get         ブラウザからサーバーへ、「サーバーからブラウザに固有の情報を返す」ように命令する。単にウェブサイトを閲覧する際にはこのメソッドが利用されている。
post ブラウザからサーバーに「ある情報」を送信するためのもの。情報の登録などの際、サーバーに情報を送信するために利用される。

form_tagメソッドによって、どのようなリクエストを送信するかが決まったので、その通りルーティングを設定する。この時動かすアクションは、先ほどtweets_controllerに記述したcreateアクションである。

config/routes.rb
1
2
3
4
5
  Rails.application.routes.draw do
    get   'tweets'      =>  'tweets#index'     #ツイート一覧画面
    get   'tweets/new'  =>  'tweets#new'       #ツイート投稿画面
    post  'tweets'      =>  'tweets#create'    #ツイート投稿機能
  end

 

編集したroutes.rbの2行目と4行目の最初の部分の違いに注目。2行目の部分はget、4行目の部分はpostとなっている。これはHTTPリクエストの違いを表している。今回の作業ではツイートの投稿機能を実装する。ツイートは入力画面から情報としてサーバーに送信されるので、postメソッドでルーティングを設定した。

 

要点チェック

 

上記の実装でcreateアクションを作成することができたが、createアクションでは投稿画面でフォームから送信された情報を元にしてツイートを作成する必要があるため、さらに編集を加えていく。

ユーザーがフォームに入力した情報をコントローラで取得する

ユーザーがフォームに入力した値は、コントローラ内ではparamsという変数に入っている。paramsはハッシュオブジェクトだと考え、今回であれば以下のようにすることでユーザーがフォームに入力した値を取得できる。

tweets_controller内
1
2
3
4
params[:name]
=>"abe"
params[:text]
=>"hello"

ハッシュであるparamsから:nameというキーを指定している。
ここで、そもそもnameというキーはどこから来たのか?という疑問が浮かぶはず。
実はこれは、new.html.erbに書いたフォーム内のinputタグの中に属性として定義されている。

app/views/tweets/new.html.erb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<div class="contents row">
  <%= form_tag('/tweets', method: :post) do %>
    <h3>
      投稿する
    </h3>
    <input placeholder="Nickname" type="text" name="name">
    <input placeholder="Image Url" type="text" name="image">
    <textarea cols="30" name="text" placeholder="text" rows="10"></textarea>
    <input type="submit" value="SENT">
  <% end %>
</div>

6〜8行目で、input要素とtextarea要素の中にnameと呼ばれる属性が存在している。これはパラメーターのキーの名前を示している。つまり、ニックネームとして入力された情報はname、画像のURLはimage、ツイートの本文はtextというキーと一緒に送信されているということになる。

テスト投稿

キー  バリュー
name        田村隆一
image http://travel.kmusiclife.com/wp-content/uploads/2013/08/DSC_2790.jpg
text 「帰途」 言葉なんかおぼえるんじゃなかった 言葉のない世界 意味が意味にならない世界に生きていたら どんなによかったか

 params

ビューでフォームに入力された情報は、コントローラにキーと一緒にパラメーターとして送られる。このパラメーターはparamsというメソッドを使うことで取得することができる。paramsメソッドを使用する際にはparams[:キー名]という形で使用することができる。

controller内での変数 内容
params[:name]        田村隆一
params[:image] http://travel.kmusiclife.com/wp-content/uploads/2013/08/DSC_2790.jpg
params[:text] 「帰途」 言葉なんかおぼえるんじゃなかった 言葉のない世界 意味が意味にならない世界に生きていたら どんなによかったか

さて、createメソッドは、利用したクラスが関連しているテーブルに新たにレコードを作成するメソッド。その際の引数は、以下のように(保存するカラム名: 保存したい値, ・・・)した。

【例】Tweetクラスにレコードを保存する

app/controlers/tweets_controller.rb
1
Tweet.create(name: "田村隆一", image: "http://travel.kmusiclife.com/wp-content/uploads/2013/08/DSC_2790.jpg", text: "「帰途」 言葉なんか・・・")

上記の例では保存したい値を直接書き込んでいるが、毎回この部分を手動で変更するわけにもいかない。パラメーターを受け取っているparamsから適切なキーを取り出すことで、ユーザーが入力する値をテーブルに保存していける。

 app/controlers/tweets_controller.rb

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
  class TweetsController < ApplicationController

    def index
      @tweets = Tweet.all
    end

    def new
    end

    def create
      Tweet.create(name: params[:name], image: params[:image], text: params[:text])
    end

  end

 

以上でパラメーターを使用してツイートを新しく作成するための実装が終了。しかし、現状ではパラメーターにどんな情報が含まれていても受け取れる状態になっているため、セキュリティの観点から好ましくない状態にある。そのため、ストロングパラメーターというものを設定していく。

 ストロングパラメーター

ストロングパラメーターとは、指定したキーを持つパラメーターのみを受け取るようにするもの。もし悪意のあるユーザーが、不正な情報を送信しようとしたときに、ストロングパラメーターを設定しておくと、不正な情報を受け取らずに済む。

 privateメソッド

classの内部でprivateとソースコードに書くと、それ以降に定義したメソッドはclassの外部から呼び出せなくなる。

メリットは以下の2つ。

1.classの外部から呼ばれたら困るメソッドを守ることができる

  • メソッドの中には、classの外部から呼び出されてしまうとエラーを起こすメソッドも存在し得る。そんな事態を事前に防ぐことができる。

2.可読性

  • classの外部から呼び出されるメソッドを探すときに、private以下の部分は目を通さなくて良くなる
app/controlers/test_controller.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  class TestController < ApplicationController

    def test
      parameter = test_params
    end

    private
    def test_params
      params.permit(:キー名, :キー名)
    end

  end

ストロングパラメーターを設定する場合、コントローラの中に「ストロングパラメーター名_params」というメソッドを作成する。この名前はそのパラメーターに適した任意のものであって構わない。メソッドの中にはparams.permitと記述し、そのあとに受取ることを許可するパラメーターのキー名を記述する。

app/controlers/tweets_controller.rb
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
  class TweetsController < ApplicationController

    def index
      @tweets = Tweet.all
    end

    def new
    end

    def create
      Tweet.create(tweet_params)
    end

    private
    def tweet_params
      params.permit(:name, :image, :text)
    end

  end

以上のコードの処理の流れ。

10行目のcreateアクションがリクエストされると、11行目の処理が行われる。tweetsテーブルにレコードを作成するcreateメソッドの引数が(tweet_params)となっているので、15行目のtweet_paramsメソッドが呼び出される。

ということは、この部分に入る値はtweet_paramsメソッドの返り値、ということになる。

メソッドの返り値は、そのメソッドの中で最後に実行されている式の値なので、tweet_paramsメソッドの返り値は、tweet_paramsの中での最後の式である16行目の式の値がtweet_paramsメソッド自体の返り値となる

16行目で利用されているpermitというメソッドは、ビューから送られてきた情報のハッシュであるparamsの中から:name:image:textというキーとそのバリューのセットだけを残した新たなハッシュを生成している。この新たなハッシュが、tweet_paramsメソッドの返り値。

つまり、11行目のtweet_paramsの値は、以下のようになっている。

app/controlers/tweets_controller.rb
1
2
#バリューは例です
{name: "田村隆一", image: "http://travel.kmusiclife.com/wp-content/uploads/2013/08/DSC_2790.jpg", text: "「帰途」 言葉なんか・・・"}

これは、createメソッドが要求する引数の形と一致している。tweet_paramsメソッドで、createメソッドの引数をまとめて管理している、と考えることもできる。

 

16行目以降にtweet_paramsというメソッドが定義してあるが、これがストロングパラメーター。このストロングパラメーターではnameimagetextというキーを持ったパラメーターのみを受け取る。

 

要点チェック

 

ビューファイルを作成

コントローラのアクションひとつに対して、ひとつのビューが存在するので、今回新しく作成したcreateアクションに対してもビューを設定していく。

今回作成するのはcreateアクションに対してのビュー。このビューが呼び出されるのは、createアクションで処理が行われたあと、つまりツイートが新規作成された後ということになる。そこでこのビューファイルは投稿が完了したことを知らせるようなビューにしていく。

 「create.html.erb」というファイルを以下のディレクトリに作成

  •  app
    •  views
      •  tweets
        •  create.html.erb
app/views/tweets/create.html.erb
1
2
3
4
5
6
7
8
  <div class="contents row">
    <div class="success">
      <h3>
        投稿が完了しました。
      </h3>
      <a class="btn" href="/tweets">投稿一覧へ戻る</a>
    </div>
  </div>

動作確認を行う

実際にアプリケーションを動かして、動作の確認を行う。http://localhost:3000/tweets/new

 実際に投稿を行う

動作確認1

動作確認2

 投稿したツイートは画面の一番下。

動作確認3