質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

1900閲覧

Ruby on Rails:ユーザー登録でsaveができない。

frusciante

総合スコア8

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2020/02/07 08:03

編集2020/02/07 08:09

前提・実現したいこと

現在、Ruby on Railsでアプリ開発中です。sessionを使用したウィザード形式のユーザー登録フォーム実装にて、最後に呼び出されるアクションに.saveを記述しているのですが、NoMethodErrorが表示されてしまい保存ができません。
エラー表示のキャプチャ
お手数ですが、ご助言いただけますと幸いでございます。よろしくお願いいたします。

該当のソースコード

  • registrations_controller.rb
# frozen_string_literal: true class Users::RegistrationsController < Devise::RegistrationsController before_action :configure_sign_up_params, only: [:performance] # before_action :configure_sign_up_params, only: [:create] # before_action :configure_account_update_params, only: [:update] # GET /resource/sign_up def new @user = User.new end def performance @user = User.new(sign_up_params) session["devise.regist_data"] = {user: @user.attributes} session["devise.regist_data"][:user]["password"] = params[:user][:password] # @user = User.new(session["devise.regist_data"]["user"]) # unless @user.valid? # flash.now[:alert] = @user.errors.full_messages # render :new and return # end end def done @user = User.new(session["devise.regist_data"]["user"]) session["devise.regist_data"] = {user: @user.attributes} session["devise.regist_data"][:user]["prefecture"] = params[:user][:prefecture] session["devise.regist_data"][:user]["introduction"] = params[:user][:introduction] session["devise.regist_data"][:user]["performance"] = params[:user][:performance] session["devise.regist_data"][:user]["portfolio"] = params[:user][:portfolio] @user = session["devise.regist_data"][:user] # binding.pry @user.save sign_in(:user, @user) end # POST /resource # def create # super # end # GET /resource/edit # def edit # super # end # PUT /resource # def update # super # end # DELETE /resource # def destroy # super # end # GET /resource/cancel # Forces the session data which is usually expired after sign # in to be expired now. This is useful if the user wants to # cancel oauth signing in/up in the middle of the process, # removing all OAuth session data. # def cancel # super # end # protected # If you have extra params to permit, append them to the sanitizer. def configure_sign_up_params devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute]) end # If you have extra params to permit, append them to the sanitizer. # def configure_account_update_params # devise_parameter_sanitizer.permit(:account_update, keys: [:attribute]) # end # The path used after sign up. # def after_sign_up_path_for(resource) # super(resource) # end # The path used after sign up for inactive accounts. # def after_inactive_sign_up_path_for(resource) # super(resource) # end end
  • application_controller.rb
class ApplicationController < ActionController::Base before_action :configure_permitted_parameters, if: :devise_controller? protected def configure_permitted_parameters devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :name_kana, :tel, :birthday, :status, :prefecture, :introduction, :performance, :portfolio]) end end
  • user.rb
class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable validates :name, :name_kana, :tel, :birthday, :status ,presence: true validates :tel, uniqueness: true enum status: { 公開:1,非公開:2 }, _prefix: true enum prefecture: { 北海道:1,青森県:2,岩手県:3,宮城県:4,秋田県:5,山形県:6,福島県:7, 茨城県:8,栃木県:9,群馬県:10,埼玉県:11,千葉県:12,東京都:13,神奈川県:14, 新潟県:15,富山県:16,石川県:17,福井県:18,山梨県:19,長野県:20, 岐阜県:21,静岡県:22,愛知県:23,三重県:24, 滋賀県:25,京都府:26,大阪府:27,兵庫県:28,奈良県:29,和歌山県:30, 鳥取県:31,島根県:32,岡山県:33,広島県:34,山口県:35, 徳島県:36,香川県:37,愛媛県:38,高知県:39, 福岡県:40,佐賀県:41,長崎県:42,熊本県:43,大分県:44,宮崎県:45,鹿児島県:46,沖縄県:47, その他:99 }, _prefix: true end
  • new.html.haml
%h2 会員情報入力フォーム = form_for(@user, url: performance_path) do |f| = render "devise/shared/error_messages", resource: @user .name .name__title お名前(全角) .name__required 必須 = f.text_field :name, autofocus: true, autocomplete: "name", placeholder: "例)山田太郎" ,class: 'name-form' .name_kana .name_kana__title お名前カナ(全角) .name_kana__required 必須 = f.text_field :name_kana, autofocus: true, autocomplete: "name_kana", placeholder: "例)ヤマダタロウ" ,class: 'name_kana-form' .email .email__title メールアドレス .email__required 必須 = f.email_field :email, autocomplete: "email", placeholder: "PC・携帯どちらでも可" .password .password__title パスワード(半角英数字) .password__required 必須 = f.password_field :password, autocomplete: "new-password", placeholder: "6文字以上の半角英数字" .tel .tel__title 携帯電話の番号 .tel__required 必須 = f.text_field :tel, autofocus: true, autocomplete: "tel", placeholder: "携帯電話の番号を入力" .birthday .birthday__title 生年月日 .birthday__required 必須 .birthday__select-form != sprintf(f.date_select(:birthday, prefix:'user', with_css_classes:'XXXXX', prompt:"--", use_month_numbers:true, start_year:Time.now.year, end_year:1900, date_separator:'%s'),'年','月')+'日' .status .status__title 会員情報の公開設定 .status__required 必須 .status__select-form = f.select :status, User.statuses.keys, {promt: "---"} .actions = f.submit "次へ" -# = render "users/shared/links"
  • performance.html.haml
%h2 活動実績入力フォーム ※お仕事をご希望の方やクリエイターの方は、以下の項目(任意)をご入力ください。 %br ※会員登録のみ、または、お仕事のご依頼のみをご希望の方は何も入力せず、「会員登録する」のボタンをクリックしてください。 = form_for(@user, url: done_path) do |f| = render "devise/shared/error_messages", resource: @user .prefecture .prefecture__title 都道府県 .prefecture__select-form = f.select :prefecture, User.prefectures.keys, {promt: "---"} .introduction .introduction__title 自己紹介 = f.text_field :introduction, autofocus: true, autocomplete: "introduction", placeholder: "200文字程度で自己紹介文をご入力ください" ,class: 'introduction-form' .performance .performance__title 活動実績 = f.text_field :performance, autofocus: true, autocomplete: "performance", placeholder: "これまでの活動実績をご入力ください" ,class: 'performance-form' .portfolio .portfolio__title ポートフォリオなどの参考URL = f.url_field :portfolio, autofocus: true, autocomplete: "portfolio", placeholder: "" ,class: 'portfolio-form' .actions = f.submit "会員登録する" -# = render "users/shared/links"

試したこと

######①「@user.save」の『@user』に値が入っているか確認。
saveの直前でbinding.pryを記述し、ターミナルで@userの中身を確認しましたが、意図した値は入っておりました。
ターミナルのキャプチャ

######② 送っている値のキーがストロングパラメーターのキーと対応しているか確認。
application_controller.rbで定義しているストロングパラメーターのキーとsessionで記述しているキーが同じか確認しました。また、Usersテーブルのマイグレーションファイルのカラム名とも照らし合わせましたが、スペルミス等は無さそうでした。

######③ 「@user.save」を「@user.save!」に変更して再度実行。
.save!に修正して試しましたが、同様のエラー文が表示されてしまいました。

開発環境

  • ruby 2.5.1
  • Rails 5.2.4.1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

registrations_controller.rbの32行目

@user = session["devise.regist_data"][:user]

@user に再代入して、 Hash オブジェクトに変えてしまってるのが原因ですね。

投稿2020/02/07 08:10

編集2020/02/07 08:13
fukajun

総合スコア17

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

frusciante

2020/02/07 08:39

ご返信いただきありがとうございます! すみません。頂いたアドバイスを参考に「rails session hashオブジェクト」等のワードで自分なりに調べてみたのですが、解決にたどりつけませんでした。 ``` @user = session["devise.regist_data"][:user] ``` について、下記2点お伺いさせていただきたく存じます。 ① @user = session["devise.regist_data"][:user] の代入記述が誤っているという事でしょうか。 ②そもそも、@userに代入して、@user.saveで保存させる工程自体が誤っているという事でしょうか。
fukajun

2020/02/07 09:16

① 代入していることが間違いです。 ② ①の回答と同じですが、`@user = session["devise.regist_data"][:user]` を行ったあとに saveを実行していることが間違いです。 一旦no method errorの解決に絞って話をすると、この行を削除するとsaveを実行できるようになるはずです。 sessionに格納している入力情報を@userにいれてsaveしたいようであれば、doneメソッドの中を 下記のように修正することで動きそうですがどうでしょうか? ``` def done session["devise.regist_data"][:user]["prefecture"] = params[:user][:prefecture] session["devise.regist_data"][:user]["introduction"] = params[:user][:introduction] session["devise.regist_data"][:user]["performance"] = params[:user][:performance] session["devise.regist_data"][:user]["portfolio"] = params[:user][:portfolio] @user = User.new(session["devise.regist_data"]["user"]) @user.save sign_in(:user, @user) end ```
frusciante

2020/02/07 09:47

ご返信いただきありがとうございます! 頂いた記述を参考に以下試してみたのですが、上手く保存がされませんでした。 ========= ■ 試した事 ① doneアクションを頂いた記述で実行したところ、no method errorが表示されてしまいました。 エラー文キャプチャ:https://gyazo.com/e9f5d12a446ba80664d13b2fe105adbe ②下記記述で再度試したところ、saveは動いたようなのですが、@userの値が全てnilになり保存がされませんでした。 ※マークダウンが使用できないようなので、エディタのキャプチャを貼らせていただきます。 エディタキャプチャ:https://gyazo.com/df6ebd3f5a55476b970f3b91e71a19fd ※ターミナルでbinding.pryを書き確認したところ、session["devise.regist_data"][:user]には値が入っていましたが、代入した@userの値はnilになっていました。 ターミナルキャプチャ:https://gyazo.com/12f485433e15403ef089a413f19fce02
frusciante

2020/02/07 10:27 編集

追加で試した事を報告させていただきます。 @user = User.new(session["devise.regist_data"]["user"]) の『["user"]』を『[:user]』に変更し、 @user = User.new(session["devise.regist_data"][:user]) で試したところ、@user の値は期待通りに取れ、saveでもエラー表示はなくなったのですが、DBへの保存がされない状況です。 エディタキャプチャ:https://gyazo.com/e870e59ba3abd62ee6691fd83720f4c5 ターミナルキャプチャ:https://gyazo.com/42504386a5175e5a5c0cca5b3667ca6c
fukajun

2020/02/07 13:36 編集

返信が遅くなり申し訳ないです。 最初の @user = User.new(session["devise.regist_data"]["user"]) の部分も、:userに変更してみてください。
fukajun

2020/02/07 13:39

pryしている箇所で、 @user.valid?を実行したあとに、@user.errorsを実行してみてください。 保存されない原因がわかるメッセージが表示されるかもしれないです。
frusciante

2020/02/08 06:29

いえとんでもないです...!こちらこそご返信が遅くなり申し訳ありません! doneの最初の記述を @user = User.new(session["devise.regist_data"][:user])に変更する件ですが、こちらは試した結果、以下のエラーが表示されてしまったので、一旦、元の記述に戻しました。 エラー画面キャプチャ:https://gyazo.com/24ecf326edffe8222f0909458bded0e2 また、その後、他の方法も試してみた結果、DB保存までは至っていないのですが、 @userにpasswordの値を渡せていない事が分かりました。 次のコメントで、試した事をまとめさせていただきます。
frusciante

2020/02/08 12:43 編集

■試した事 ====== ① @user.saveを@user.save! に変更してエラー画面を表示させた。 エラー画面キャプチャ:https://gyazo.com/796c2b90d815f8bfcfa637435430f0f8 エディタキャプチャ:https://gyazo.com/28da9276c1b49593d4a69ee137091ed7 ====== ② doneの最初の記述 @user = User.new(session["devise.regist_data"]["user"]) の段階で、passwordが@userに入っているかbinding.pryで確認。 エディタキャプチャ:https://gyazo.com/d591a8ed736fd79f41f3d33a1facbd2c ターミナルキャプチャ:https://gyazo.com/934e7f9b6553a82fbba0cccec7df6f37 結果、以下の事が把握できました。 ・@user ⇨ passwordが入っていない ・session["devise.regist_data"]["user"] ⇨ passwordが入っている ・User.new(session["devise.regist_data"]["user"]) ⇨ passwordが入っていない ====== 以上の事を試し、 User.new(session["devise.regist_data"]["user"]) に、 passwordのキーも値も入っていないので、対処方法を調べている状況となります。
frusciante

2020/02/08 12:43

すみません、まだ解決はできていないのですが、問題の内容が変わってきた為、改めて質問を投稿させていただきました。恐縮ですが、ご確認いただけますと幸いです。よろしくお願いいたします。 https://teratail.com/questions/240230
fukajun

2020/02/08 18:41 編集

すみません、直接解決につながるようなコメントができず申し訳ないです。 <コードを見直した結果、コチラの認識と現状がことなるようので、コメントを一部削除しました。>
frusciante

2020/02/08 18:59

いえ、とんでもないです!!色々試した結果、たった今解決ができました! 仰せの通り、「アクションをまたぐ事でキーがシンボルから文字列になる」という記事を先ほどQiitaで見つけ、doneアクションのsession記述を文字列で書くことにより、保存させる事に成功しました! ※今日から sessionを書くときは、エラー原因を減らす為、文字列で統一したいと思います。 また、passwordが保存されない問題については、恐らく session["devise.regist_data"] = {user: @user.attributes} をdoneアクションで再度記述した事により、passwordがsessionの中に入らなくなってしまったのだと思います。 ※1ページ目の入力情報まで(performanceアクションまで)でユーザー登録するテストをしたのですが、無事登録ができた為、気づきました...。 ※{"user" => @user.attributes}、こちらも文字列で記述するのを後ほど試してみたいと思います! fukajun様のおかげでエラー原因の範囲特定がかなり進みましたので、誠に感謝いたします! ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問