ぴよログ

↓に移転したのでこっちは更新されません、多分。

Deviseで生成したユーザーの更新フォームに自前のフィールドを追加する

移転しました →

Rails4+Deviseの話。Deviseでユーザーを作るとデフォルトでユーザー情報更新フォームがついてくる。これはbootstrapでスタイル付けしてあるものだけど、基本はこんな感じになる。

このUserモデルに対して別のフィールドをいくつか追加した上で、同じフォームで更新可能にするにはどうしたらいいのか、というのが今日のテーマ。

例えば名前とか、表示名とか、住所とか、そういう情報がアプリケーションに依っては必要になってくると思う。

今回はnameというカラムをUserに持たせることにする。なお、add_column :users, :name, :stringみたいなマイグレーションは既に済んでいるとする。

DeviseのカスタムViewを用意する

% rails generate devise:views

このコマンドによってアプリケーションディレクトリ内にdevise用のビューが生成される。ちなみに先ほどのスクリーンショットは生成したビューを日本語化したもの。

これをやっておくことでDeviseのコントローラが表示に使うビューを自由に変更することができる。

registrations/edit.html.hamlを編集する

erbの人は随時読み替えてもらえばOK。app/views/devise/registrations/edit.html.hamlname用のフィールドを追加する。

例えばこんな感じで3行ほど追加する。

  %h2
    アカウント情報更新
  = form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put, role:"form" }) do |f|
    = devise_error_messages!
    -# この3行を追加 ##################################################
    .form-group
      = f.label :name, "名前"
      = f.text_field :name, :autofocus => true, class:"form-control"
    -# ##############################################################
    .form-group
      = f.label :email, "Eメール"
      = f.email_field :email, class:"form-control"
    - if devise_mapping.confirmable? && resource.pending_reconfirmation?
      .form-control
        Currently waiting confirmation for: #{resource.unconfirmed_email}
    .form-group
      = f.label :password, "パスワード"
      %i (パスワードを変更しない場合は空欄のままにしてください)
      = f.password_field :password, :autocomplete => "off", class:"form-control"
    .form-group
      = f.label :password_confirmation, "パスワード(再入力)"
      = f.password_field :password_confirmation, class:"form-control"
    .form-group
      = f.label :current_password, "現在のパスワード"
      %i (更新するために現在のパスワードが必要です。)
      = f.password_field :current_password, class:"form-control"
    .form-group
      = f.submit "更新", class:"btn btn-primary"
  %h3 退会
  %p
    退会してユーザー情報を削除しますか? #{button_to "退会する", registration_path(resource_name), :data => { :confirm => "よろしいですか?" }, :method => :delete, class:"btn btn-danger"}
  = link_to "戻る", :back

さあこれでフォームができたからもう動くだろうと思ってみると実際にはそうはいかない。Rails4から導入されているStrong Parametersの概念により、許可されていないnameを更新できないというエラーが発生してしまうからだ。

Devise用のコントローラを作る

nameの更新を許可するため、Deviseのコントローラを継承したものを用意する必要がある。このコントローラでは、更新のためのupdateアクションでのみnameパラメータを追加でpermitするという処理を行い、それ以外はベースクラスであるDevise::RegistrationsControllerでDevise従来の処理を行う。

# app/controllers/users/registrations_constroller.rb
class Users::RegistrationsController < Devise::RegistrationsController

  before_action :configure_permitted_parameters, only: [:update]

  private 
  
  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:account_update) do |u|
      u.permit(:name,
        :email, :password, :password_confirmation, :current_password)
    end
  end  
 
end

パラメータの許可はdevise_parameter_sanitizerというDevise用のオブジェクトを経由して行われていて、この部分で:nameも許可対象として指定してあげれば良い。

そしてconfig/routes.rbを編集し、新しく作ったUsers::RegistrationsControllerを使うようにルートを書き換えればよい。

# before
devise_for :users

# after
devise_for :users, controllers: {
  registrations: 'users/registrations'
}

完成!