アプリ開発実践入門5 Controllerとview メッセージボード

今日の教科書

#メッセージボードを作る
名前・メアド・メッセージを記入し送信するフォームの下に一覧でメッセージを表示し時間経過で消去するプログラム。

##コントローラの作成

`rails generate controller コントローラ名 アクション名`：コントローラとアクションを作成するジェネレーションコマンド。アクションが作成される際は、アクションメソッド、ビューテンプレート、ルート設定がデフォルトで用意される。

##ビューHTMLテンプレートの編集

フォームの表示と投稿したメッセージのテーブル表示の二つを作成する。
フォームについては割愛。

###ハッシュをテーブルに展開する

```
<% @msg_data.each do |key,obj| %>
<tr>
  <td class="msg"><%= obj['msg'] %></td>
  ・
  ・
  <td class="time"><%= Time.at(key.to_i) %></td>
</tr>
<% end %>
```

インスタンス変数の中身を取り出して、テーブルのセルとして記述する。valueのところが、objになっているのは値がオブジェクトだから。

```
ハッシュ.each do |変数1,変数2| %
処理
end
```

ハッシュから値を順番に取り出し、キーと値を変数1,2に代入した後、処理を実行する。

`<%= Time.at(key.to_i) %>`：キーの値から投稿日時を表示する。元のインスタンス変数にはキーはその投稿の日時のタイムスタンプを示す整数が設定されている。それを引数にTimeオブジェクトを生成する。`to_i`は数を整数として取り出すメソッド。

##レイアウトファイルを作る

layoutsフォルダにレイアウトのhtmlファイルを作成。割愛。

##コントローラを作成


###保存したデータを管理するMydataクラス
フォームから送信されたデータをこのクラスのインスタンスに保管。データはテキストファイルに変換されて保存される。ハッシュ形式でデータをまとめておくため間にインスタンスを利用している。

attr_accessor：インスタンス変数へのアクセスするメソッドを用意するためのもの。これでname,mail,msgなどのインスタンス変数を用意し、外からでも利用できる用意する。

###データの保存

```
def index
  if request.post? then
    obj = MyData.new(msg:params['msg'], name:params['name'],
      mail:params['mail'])
    @msg_data[Time.now.to_i] = obj
    data = @msg_data.to_json
    File.write("data.txt", data)
    @msg_data = JSON.parse(data)
  end
end
```

####MyDataの作成

`if request.post? then`でPOSTされたかチェックして処理している。

`obj = MyData.new(msg:params['msg'], name:params['name'],
      mail:params['mail'])`で変数objにMyDataインスタンスが用意される。
`@msg_data[Time.now.to_i] = obj`：@msg_dataはハッシュ。このハッシュに現在のタイムスタンプをキーにしてMyDataインスタンスを保管する。Time.nowで現在の日時を示すTimeインスタンスを作成しto_iメソッドで呼び出すことでタイムスタンプを作る。これをキーとしてobjを保存。

####JSONでデータを保管
JSONを使って保存している。JavaScriptのオブジェクトを保存するフォーマット。Rubyでも使える。

`data = @msg_data.to_json`：@msg_dataのハッシュをJSONのテキストにして取り出す。to_jsonで行える。

`File.write("data.txt", data)`：テキストファイルとして保存するためにFileクラスのwriteメソッドを使う。引数にファイル名と保存するテキストを指定する。

`@msg_data = JSON.parse(data)`：JSONのテキストデータを元にオブジェクト生成して@msg_dataに収める。

###データの読み込み

```
def initialize
  super
  bigin
    @msg_data = JSON.parse(File.read("data.txt"))
  rescue
    @msg_data = Hash.new
  end
  @msg_data.each do |key,obj|
    if Time.now.to_i - key.to_i > 24*60*60 then
      @msg_data.delete(key)
    end
  end
  File.write("data.txt", @msg_data.to_json)
end
```

initializeメソッドでインスタンスを作る際に初期化されるようになる。
`super`：子クラスのインスタンスに対して、同名の親クラスのメソッドをそのまま呼び出すことが出来る([詳細](https://qiita.com/mao-0901/items/906587ad9c4108d70b62))

```
bigin
    @msg_data = JSON.parse(File.read("data.txt"))
  rescue
    @msg_data = Hash.new
end
```

ファイルからテキストを読み込みRubyオブジェクトに変換する。
`File.read`：引数のファイルをテキストに読み込んで返す。
`JSON.parse`：JSONのテキストでRubyオブジェクトを生成する。

File.readではファイルの読み込みに失敗する場合がある。ファイルが存在しないときも同様。

```
begin
例外が発生するかもしれない処理
rescue
例外が発生した際の処理
end
```

このようにrescueに移動して処理する。ここでは新しいハッシュを作る。

####一日経過したデータを削除する
@msg_datamにハッシュを設定したら、値をチェックし24時間以上経過したら取り除く処理。

```
@msg_data.each do |key,obj|
    if Time.now.to_i - key.to_i > 24*60*60 then
      @msg_data.delete(key)
    end
  end
File.write("data.txt", @msg_data.to_json)
```

eachで順にキーと値を取り出す。Time.nowで現在の日時とキーに保管されているタイムスタンプの日時の差が一日より多かったら、deleteでデータを取り除く。
そして、古いデータが削除されたのでFile.writeでハッシュをテキストファイルに保存し直して終了。

##ルーティングの設定
割愛。