会計ソフトを作ってみよう

## はじめに

会計ソフトみたいなものを作ってみようと思い、少し着手し始めました。今回はnested_formを試したので、それを紹介したいと思います。

やってみたこと、課題、参照したサイトなどを紹介します。

![nested_form.gif](https://qiita-image-store.s3.amazonaws.com/0/29884/77c13604-0dd9-3d27-465a-406eb0eb24d8.gif)

## やってみたこと

次のコマンドを実行しました。

``` sh
$ rails new sample_app
$ cd sample_app
$ vim Gemfile
$ bundle install
$ rails generate scaffold Entry date:date comment:text
$ rails generate scaffold Debit name:string money:integer entry_id:integer
$ rails generate scaffold Credit name:string money:integer entry_id:integer
$ rake db:migrate
$ vim app/assets/javascripts/application.js
$ vim app/models/entry.rb
$ vim app/models/debit.rb
$ vim app/models/credit.rb
$ vim app/controllers/entries_controller.rb
$ vim app/views/entries/_form.html.erb
```

編集対象のファイルはrailsコマンドで自動生成されます。編集対象のファイルはvimコマンドを実行したところです。（実際には何度もvimコマンドを実行することはありません。vimのノーマルモードで`:e {file}`とタイプすれば、ファイルを編集することができます。）

まずは、Gemfileを編集します。次の行を追加します。

``` Gemfile
gem 'nested_form'
```

次に、application.jsを編集します。次の行を追加します。

``` application.js
//= require jquery_nested_form
```

モデル間の関連は次のように実装します。

``` entry.rb
class Entry < ActiveRecord::Base
  has_many :credits
  has_many :debits
  accepts_nested_attributes_for :credits, allow_destroy: true
  accepts_nested_attributes_for :debits, allow_destroy: true
end
```

``` debit.rb
class Debit < ActiveRecord::Base
  belongs_to :entry
end
```

``` credit.rb
class Credit < ActiveRecord::Base
  belongs_to :entry
end
```

Strong Parametersというのがよく分かっていないのですが、ビュー側でentryが参照しているdebits, credits（に含まれるオブジェクト）の属性にアクセスするためにStrong Parametersを使っているようです。

これらを実装するために、コントローラーに実装を追加します。

``` entries_controller.rb
class EntriesController < ApplicationController

(中略)

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_entry
      @entry = Entry.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def entry_params
      params.require(:entry).permit(:date, :comment, debits_attributes: [:name, :money, :entry_id, :_destroy], credits_attributes: [:name, :money, :entry_id, :_destroy])
    end
end
```

ビューは次のように実装しました。

``` _form.html.erb
<%= nested_form_for(@entry) do |f| %>
  <% if @entry.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@entry.errors.count, "error") %> prohibited this entry from being saved:</h2>

      <ul>
      <% @entry.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :date %><br>
    <%= f.date_select :date %>
  </div>
  <div class="field">
    <%= f.label :comment %><br>
    <%= f.text_area :comment %>
  </div>
  <div class="field">
    <%= f.fields_for :debits do |debit| %>
      <%= debit.text_field :name %>
      <%= debit.text_field :money %>
      <%= debit.link_to_remove "Remove this debit" %>
    <% end %>
    <p><%= f.link_to_add "Add debit", :debits %></p>
  </div>
  <div class="field">
    <%= f.fields_for :credits do |credit| %>
      <%= credit.text_field :name %>
      <%= credit.text_field :money %>
      <%= credit.link_to_remove "Remove this credit" %>
    <% end %>
    <p><%= f.link_to_add "Add credit", :credits %></p>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>
```

ここまでで冒頭のgifのような機能が実現されると思います。

## 課題

newとeditで同じ_form.html.erbを使っているので、更新しただけで、データが追加されてしまいます。

ほかにもたくさん課題がありそうです。。。

よく分かっていないのですが、debits, creditsのentry_idがなぜか自動で更新されました。どうやって更新しようか悩んでいたのですが、自動で更新されて少し驚きました。なぜなんでしょうか？

## 参照

- [Rails4で　１対多、多対多関連しているときのフォームを作るなら、Nested Form Gemが便利](http://qiita.com/regonn/items/cdbda32900a15721d59b)
- [ryanb/nested_form](https://github.com/ryanb/nested_form)