前提・実現したいこと
Railsでユーザーのプロフィール画面を作っています。
ユーザーが「今勉強中の言語」を選択出来るよう、language-selectと言うgemを使用し実装しました。またユーザーは複数の言語を勉強中の可能性もある為、今度はcocoonと言うgemを使用し、言語選択のセレクトタグを非同期で追加・削除出来るようにしました。
しかしここからが問題で、ユーザーが最初に選んだ言語はしっかり保存されるのですが、cocoonにより追加し選択した言語はうまく保存されません。
ユーザーが追加・選択した情報もうまく保存し、プロフィール画面に表示させたいです。
問題に至るまでの流れ
cocoonの実装はgithubのREADMEやこちらのページを参考に行いました。
しかし同じコードでは「保存」ボタンを押しても何も反応が無かったので、該当しているであろうform_forのメソッドをpostにしました。
Rails
1<%= form_for @user, method: :post do |f| %> 2 <div id='languages'> 3 <%= f.fields_for :languages do |language| %> 4 <%= render 'language_fields', :f => language %> 5 <% end %> 6 <div class='links'> 7 <%= link_to_add_association 'add language', f, :languages %> 8 </div> 9 </div> 10<% end %>
すると反応はするようになりましたが今度は以下のエラーが表示されました。
ActionController::InvalidAuthenticityToken in UsersController#update ActionController::InvalidAuthenticityToken Extracted source (around line #211): def handle_unverified_request raise ActionController::InvalidAuthenticityToken end end end
こちらはapplication_controller.rbに「protect_from_forgery with: :null_session」の一文を追加する事で解消されました。
ようやく実装の確認が出来るかと思ったのですが、ここで上記で触れたように、ユーザーが最初に選んだ言語は保存されるが、cocoonにより追加し選択した言語は保存されない、と言う問題が発生しました。
該当のソースコード(users#show.html.erb)
rails
1<h2><%= @user.language %></h2>
該当のソースコード(users#edit.html.erb)
rails
1 <%= form_tag("/users/#{@user.id}/update", {multipart: true}) do %> 2 <table> 3 <p>言語</p> 4 <%= select_tag(:language,options_for_select(languages)) %> 5 <%= render 'users/form' %> 6 <input type="submit" value="保存"> 7 </table> 8 <% end %>
該当のソースコード(users#_form.html.erb)
cocoonのパーシャルです。
rails
1<%= form_for @user, method: :post do |f| %> 2 <div id='languages'> 3 <%= f.fields_for :languages do |language| %> 4 <%= render 'language_fields', :f => language %> 5 <% end %> 6 <div class='links'> 7 <%= link_to_add_association 'add language', f, :languages %> 8 </div> 9 </div> 10<% end %>
該当のソースコード(users#_language.html.erb)
cocoonのパーシャルの2つ目です。
rails
1<div class='nested-fields'> 2 <div class="field"> 3 <%= select_tag(:language,options_for_select(languages)) %> 4 </div> 5 <%= link_to_remove_association "remove language", f %> 6</div>
該当のソースコード(users_controller.rb)
またここで「redirect_to("/users/#{@user.id}")」と設定しているのですが、application_controller.rbに「protect_from_forgery with: :null_session」の一文を入れた直後は該当ページにリダイレクトされますが、それ以降は「/posts/index」にリダイレクトされてしまいます。その際、application_controller.rbのforbid_login_userで設定した"すでにログインしています"のフラッシュも表示されます。
rails
1 before_action :authenticate_user, {only: [:index, :show, :edit, :update]} 2 before_action :forbid_login_user, {only: [:new, :create, :login_form, :login]} 3 before_action :ensure_correct_user, {only: [:edit, :update]} 4 5 def edit 6 @user = User.find_by(id: params[:id]) 7 end 8 9 def user_params 10 params.require(:user).permit(:name, :description, languages_attributes: [:id, :description, :done, :_destroy]) 11 end 12 13 def update 14 @user = User.find_by(id: params[:id]) 15 @user.language = params[:language] 16 if params[:image] 17 @user.image_name = "#{@user.id}.jpg" 18 image = params[:image] 19 File.binwrite("public/user_images/#{@user.image_name}", image.read) 20 end 21 if params[:cover_image] 22 @user.cover_image_name = "#{@user.id}_cover.jpg" 23 cover_image = params[:cover_image] 24 File.binwrite("public/user_cover_images/#{@user.cover_image_name}", cover_image.read) 25 end 26 if @user.save 27 flash[:notice] = "ユーザー情報を編集しました" 28 redirect_to("/users/#{@user.id}") 29 else 30 render("users/edit") 31 end 32 end
該当のソースコード(application_controller.rb)
rails
1class ApplicationController < ActionController::Base 2 protect_from_forgery with: :null_session 3 before_action :set_current_user 4 5 def set_current_user 6 @current_user = User.find_by(id: session[:user_id]) 7 end 8 9 def authenticate_user 10 if @current_user == nil 11 flash[:notice] = "ログインが必要です" 12 redirect_to("/login") 13 end 14 end 15 16 def forbid_login_user 17 if @current_user 18 flash[:notice] = "すでにログインしています" 19 redirect_to("/posts/index") 20 end 21 end 22end
他に必要なコードがありましたら追記致します。どなたかお知恵を拝借頂けると幸いです。
補足情報(FW/ツールのバージョンなど)
ruby 2.6.4p104
RubyGems 3.0.3
Rails 5.2.3
追記
まだ解決していない為、問題のあったcocoonで複製した部分はコメントアウトで一旦消して、form_tagをform_withに変える作業を先に進めておりました。するとここでも、保存ボタンを押しても内容が保存されず、「/posts/index」にリダイレクトされる問題が発生しました(おそらくforbid_login_userによるもの)。
ログイン中にはアクセスできないページ(新規登録ページ等)に行こうとしている訳ではないにも関わらず、なぜこのようなリダイレクトになってしまうのかが分かりません…。
該当のソースコード(users#edit.html.erb)
Rails
1 <%= form_with(model: User, local: true) do |f| %> 2 <p> 3 <%= f.label :ユーザー名 %> 4 <%= f.text_field :name, value: @user.name %> 5 </p> 6 <p> 7 <%= f.label :画像 %> 8 <%= f.file_field :image %> 9 </p> 10 <p> 11 <%= f.label :カバー画像 %> 12 <%= f.file_field :cover_image %> 13 </p> 14 <p> 15 <%= f.label :メールアドレス %> 16 <%= f.email_field :email, value: @user.email %> 17 </p> 18 <p> 19 <%= f.label :性別 %> 20 <%= f.radio_button :sex, :Male %>男 21 <%= f.radio_button :sex, :Female %>女 22 </p> 23 <p> 24 <%= f.label :国籍 %> 25 <%= f.country_select :country, selected: @user.country %> 26 </p> 27 <p> 28 <%= f.label :言語 %> 29 <%= select_tag(:language, options_for_select(languages)) %> 30 </p> 31 <p> 32 <%= f.label :自己紹介 %> 33 <%= f.text_area :introduction, rows: "10", cols: "100", value: @user.introduction %> 34 </p> 35 <%= f.submit "保存" %> 36 <% end %>
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。