deviseから複数モデルへの保存

# 実現したかったこと
deviseのアカウント登録の際に２つのモデルに記録させたい。
（ユーザー情報と会社情報）

# どうして？
下記の問題が起こるため。

- Followテーブル
CampanyとUserそれぞれで User Aさんをフォローしたかった。

# 問題箇所
フォロー機能実装の際にCampany（モデル）とUser（モデル）で登録したユーザーは同じ番号のidを持っている。
┗Campanyページからアカウント登録を行った際の１番目のユーザーidは１番。
┗Userページからアカウントアカウント登録を行った際の１番目のユーザーidは１番。
Followテーブルにfollowerとして情報を記録する際に後々の紐付けのためにidを残したいがCampanyとUserはそれぞれ違うテーブルから来たid情報。
id 1となり重複してしますので、この方法は良くなかった。
![スクリーンショット 2019-04-02 21.58.28.png](https://qiita-image-store.s3.amazonaws.com/0/383660/ec18945c-b804-ae04-bd0a-ff9788811226.png)


# 考えた解決方法
法人（Campany）もUserとみなしUserテーブルに登録する。
ただし法人情報は子モデルとしてCampaniesテーブルに登録する。

# 準備
deviseのデフォルト設定カラムに任意カラム追加

```deviseのregistrations_controller.rb
  def configure_sign_up_params
    devise_parameter_sanitizer.permit(:sign_up,
      keys: [:name, :category_id, campany_attributes: [:campany_name, :campany_logo, :category_id, :campany_url, :tel, :staff_last_name_kana, :staff_first_name_kana]])
  end
```
campany_attributes: [:campanyレコードのカラム名, :campanyレコードのカラム名, ]
モデル名_attributesとすることで親モデルに紐づけている。
(補足：campany_attributesのcampanyはhas_one関係なら単数、has_manyなら複数）

# アソシエーション設定
```user.rb
  # userモデルの中でcampanyモデルへも同時書き込み
  has_one :campany, inverse_of: :user
  accepts_nested_attributes_for :campany
```
```campany．rb
  # Userモデル中でcampanyモデルへも書き込む
  belongs_to :user, inverse_of: :campany
```


今回はnewアクションはuser登録で使用している。
法人登録は別画面にしたかったので下記のルートで準備。

```routes.rb
    get '/campany/new' => 'users/registrations#campany' ,as: :new_campany
```

参考にした記事では
@user.campany.buildでネストモデルの構造にできるとあったが、この記述だがうまく行かなかった。
下記の記法にすることで解決できた。
またcreateアクションはdeviseの機能を上書きするのでsuper以下に記述する。
最後にuser.saveとしなければ子モデル（campany）には保存されないので忘れずに。

``` deviseのregistrations_controller.rb
  # 企業の登録フォーム
  def campany
    @user = User.new
    @user.build_campany
  end

  def create
    super
    user = User.new(configure_sign_up_params)
    user.save
  end
```

注意：
子モデルへのデータの渡し方は下記のようにf.fields_forを使用する。
上下のようにインデントがきちんと整っていれば実現したいレイアウトに合わせてUserモデル、Campanyモデルへ渡すデータの位置がバラバラに置いても良い。
（親formはform_forであること）

```campany.html.erb
<h2><%= t('.sign_up') %></h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>

  <div class="field">
    <%= f.label "会社名" %><br />
    <%= f.text_field :name, autocomplete: "off" %>
  </div>

  <%= f.fields_for :campany do |campany| %>
    <div class="field">
      <%= campany.label "会社URL" %><br />
      <%= campany.text_field :campany_url, autocomplete: "off" %>
    </div>

    <div class="field">
      <%= campany.label :tel %><br />
      <%= campany.telephone_field :tel, autocomplete: "off" %>
    </div>
  <% end %>

  <div class="field">
    <%= f.label "カテゴリー" %><br />
    <%= f.collection_select :category_id, Category.all, :id, :name, {prompt: "選択してください"}%>
  </div>

  <%= f.fields_for :campany do |campany| %>
    <div class="field">
      <%= campany.label "ご担当者様　姓（カナ）" %><br />
      <%= campany.text_field :staff_last_name_kana, autocomplete: "off" %>
    </div>

    <div class="field">
      <%= campany.label "ご担当者様　名（カナ）" %><br />
      <%= campany.text_field :staff_first_name_kana, autocomplete: "off" %>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email, autofocus: true, autocomplete: "off" %>
  </div>

  <div class="field">
    <%= f.label :password %>
    <% if @minimum_password_length %>
    <em>(<%= @minimum_password_length %> characters minimum)</em>
    <% end %><br />
    <%= f.password_field :password, autocomplete: "off" %>
  </div>

  <div class="field">
    <%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation, autocomplete: "off" %>
  </div>

  <div class="actions">
    <%= f.submit t('.sign_up')%>
  </div>
<% end %>

<%= render "devise/shared/links" %>
```
![スクリーンショット 2019-04-02 20.12.45.png](https://qiita-image-store.s3.amazonaws.com/0/383660/1e361d66-6522-2116-ac53-dd6dc9cd2c87.png)

無事に２つのモデルに保存されました。


# 失敗したこと
registrations_controllerの中でcampanyメソッドを最初は**new_campany**という名前にしていた。
エラーで**new_campany_path？**と言われたがそんなはずはない。
そもそもメソッド名がprefixパスでエラー文吐き出すってどういう意味？
悩むこと3時間、**予約語**　のキーワードが頭をよぎった。
まさかと思いメソッド名を変えたところビューに無事飛んでくれた。
予約語には気をつけよう。