概要
deviseのエラーメッセージがうまく表示されないので、理由をなんとなく突き止めた。
解決とは言えないけど、decviseの仕組みが少しだけ理解できたので忘備録として残しておきます。
解決策
部分テンプレートを呼び出す時に、テンプレートに変数名をresource
から@モデル名
に変更した。
<%= render "devise/shared/error_messages", resource: resource %>
↓
<%= render "devise/shared/error_messages", resource: @profile %>
deviseは複数のモデルのインスタンスを扱えるフレームワークなので、resourceでうまく処理できるみたいです。
本当は別の処理もありそうだけど、ここを@モデル名
に変えたらうまくいきました。
その他のコード
ルーティング
ユーザー登録とプロフィール登録をウィザード形式にしているため、profileは'users/registration'コントローラーで処理させています。
※なんかここにエラーがでた理由が隠されていそうなんだけど詳しくは不明。
Rails.application.routes.draw do
devise_for :users, controllers: {
registrations: 'users/registrations'
}
devise_scope :user do
get 'profiles', to: 'users/registrations#new_profile'
post 'profiles', to: 'users/registrations#create_profile'
end
end
テーブル設計
deviseを使って、usersテーブルとprofilesテーブルにユーザー情報を保存しようとしている。
# usersテーブルとprofielsテーブルはこんな感じ。
create_table "profiles", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "favorite_beer"
t.text "twitter_link"
t.text "info"
t.bigint "user_id", null: false
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["user_id"], name: "index_profiles_on_user_id"
end
create_table "users", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
t.string "nickname", null: false
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
入力フォーム
プロフィール登録のビューはこんな感じ。
ここの部分テンプレートでエラーメッセージを呼び出しているが、そこにうまくprofilesテーブルの情報が渡せなかった様子。
<h2>プロフィール登録</h2>
<%= form_with model: @profile, local: true do |f| %>
<%= render "devise/shared/error_messages", resource: @profile %>
<div class="field">
<%= f.label :avatar %><br />
<%= f.file_field :avatar %>
</div>
<div class="field">
<%= f.label :favorite_beer %><br />
<%= f.text_field :favorite_beer, autofocus: true, autocomplete: "favorite_beer" %>
</div>
<div class="field">
<%= f.label :twitter_link %><br />
<%= f.text_field :twitter_link, autocomplete: "twitter_link" %>
</div>
<div class="field">
<%= f.label :info %><br />
<%= f.text_area :info %>
</div>
<div class="actions">
<%= f.submit "新規登録" %>
</div>
<% end %>
<%= render "devise/shared/links" %>
エラーメッセージの呼び出しもと
部分テンプレートで呼び出しているdeviseのエラーメッセージは以下の通り
<% if resource.errors.any? %>
<%# この↑の部分のresourceに@profileを渡した%>
<div id="error_explanation">
<h2>
<%= I18n.t("errors.messages.not_saved", #ここら辺の記述はdevise.ja.ymlに記載がある
count: resource.errors.count,
resource: resource.class.model_name.human.downcase)
%>
</h2>
<ul>
<% resource.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
deviseを日本語化しているファイル
deviseは既に日本語化しているので、ymlファイルも日本語になっています。
ja:
activerecord:
attributes:
# ~省略~
models:
user: ユーザ
profile: プロフィール # ここも日本語化したかったので追記しました
# ~省略~
errors:
messages:
already_confirmed: は既に登録済みです。ログインしてください。
confirmation_period_expired: の期限が切れました。%{period} までに確認する必要があります。 新しくリクエストしてください。
expired: の有効期限が切れました。新しくリクエストしてください。
not_found: は見つかりませんでした。
not_locked: は凍結されていません。
# このしたのnot_savedのところが部分テンプレートで呼び出されている様子
not_saved:
one: エラーが発生したため %{resource} は保存されませんでした。
other: "%{count} 件のエラーが発生したため %{resource} は保存されませんでした。"
まとめ
今後まだまだ勉強していきたいと思います。
もしこの文章がとんでもない勘違いを含んでいましたら、ご指摘いただければと思います。