🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

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

Q&A

解決済

2回答

1468閲覧

undefined methodを解消したいです

kurumin27

総合スコア3

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

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

0グッド

1クリップ

投稿2020/12/28 22:28

前提・実現したいこと

railsを使って簡単な予約システムを制作しております。
新規予約をしたら予約テーブルに予約日と予約時間と予約したい商品をテーブルへ保存したいのですが、以下のエラーがでてしまっています。

発生している問題・エラーメッセージ

NoMethodError in ReservationsController#create undefined method

該当のソースコード

コントローラー

ruby

1class ReservationsController < ApplicationController 2 before_action :product_name, only:[:new, :create, :edit, :update] 3 before_action :reservation_product, only:[:new, :create] 4 5 def index 6 end 7 8 def new 9 @reservation = Reservation.new 10 end 11 12 def create 13 @reservation = Reservation.create(reservation_params) 14 15 unless @reservation.save 16 render :new 17 end 18 end 19 20 def edit 21 end 22 23 def update 24 end 25 26 def destroy 27 end 28 29 30 private 31 def reservation_params 32 params.require(:reservation).permit(:date, :time, products_attributes: [:product_name, :_destroy, :id]) 33 end 34 35 def product_name 36 @products = Product.select(:product_name) 37 end 38 39 def reservation_product 40 @product = Product.where(product_name: nil) 41 end 42 43end

モデル

ruby

1class Reservation < ApplicationRecord 2 validates :date, presence: true 3 validates :time, presence: true 4 validates :product_name, presence: true 5 6 has_one :product 7 belongs_to :user 8end

newアクションのビュー

ruby

1.Body 2 .Form-box 3 = form_with model: @reservation, local: true do |f| 4 .alert 5 = render 'layouts/notifications' 6 .Form-box__content 7 = f.label :date, 'ご希望の日にち', class: "Form-box__content__title" 8 %span.Form-box__content__requirement 9 必須 10 = f.date_field :date, class: "Form-box__content__select" 11 .alert 12 = render 'layouts/notifications' 13 .Form-box__content 14 = f.label :time, 'ご希望のお時間', class: "Form-box__content__title" 15 %span.Form-box__content__requirement 16 必須 17 = f.select :time, 18 { '10:00~': 1, 19 '11:00~': 2, 20 '12:00~': 3, 21 '13:00~': 4, 22 '14:00~': 5, 23 '15:00~': 6, 24 '16:00~': 7, 25 '17:00~': 8, 26 '18:00~': 9, 27 '19:00~': 10 }, 28 { include_blank: '選択してください' }, 29 { class: "Form-box__content__select" } 30 .alert 31 = render 'layouts/notifications' 32 .Form-box__content 33 = f.label :product_name, 'ご希望のコース', class: "Form-box__content__title" 34 %span.Form-box__content__requirement 35 必須 36 = f.select :product_name, @products.map { |product| [product.product_name]}, 37 { include_blank: '選択してください' }, 38 { class: "Form-box__content__select" } 39 -# .Form-box__content 40 -# = f.label :price, 'ご希望のコースの金額', class: "Form-box__content__title" 41 -# .Form-box__content__price 42 -# %p ここに金額が表示される 円 43 .Form-box__content 44 = f.submit '予約', class: "Form-box__button"

マイグレーションファイル

ruby

1class CreateReservations < ActiveRecord::Migration[6.0] 2 def change 3 create_table :reservations do |t| 4 t.datetime :date, null: false 5 t.datetime :time, null: false 6 t.timestamps 7 end 8 end 9end

ruby

1class AddProductToReservation < ActiveRecord::Migration[6.0] 2 def change 3 add_reference :reservations, :product, null: false, foreign_key: true 4 end 5end

試したこと

①エラーではストロングパラメータが色づいていたので、ストロングパラメータを見直し、以下のように編集しましたが、変わらなかったです。
params.require(:reservation).permit(:date, :time, products_attributes: [:product_name, :_destroy, :id])
②binding.pryにてparamsと打ち込むとpermitted: falseとなりました。

補足情報(FW/ツールのバージョンなど)

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

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

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

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

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

m.ts10806

2020/12/28 22:38

一度newしてみては?
kurumin27

2020/12/29 01:13

コメントありがとうございます。 newメソッドで、確認してみました。 [3] pry(main)> reservation = Reservation.new(date:"2021-01-07", time:"3", product_name:"肌再生<90分コース>") ActiveModel::UnknownAttributeError: unknown attribute 'product_name' for Reservation. from /Users/kurumi/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/activemodel-6.0.3.4/lib/active_model/attribute_assignment.rb:52:in `_assign_attribute' 最後に「assign_attribute」と、あったので、 accepts_nested_attributes_for :product をreservationモデルへ追記してみたのですが、以下のようなエラー文がでてきました。 undefined method `product_name' for #<Reservation:0x00007f82e184a740> Did you mean? product
guest

回答2

0

自己解決

以下の方法で解決しました!
####問題と対処
①DB設計が誤っていました。
マイグレーションファイルとモデルのアソシエーションが矛盾していたので、それを修正しました。

②product_nameを直に取得してしまっていました。
product_nameはアソシエーションを組んでいるので、それを利用して、
selectメソッドではなくallメソッドですべて取得してから、ビュー側でproduct_idとproduct_nameを取得できるようにして、パラメータでは、product_idを渡すように修正しました。
コントローラーの記述は、createメソッドを使っているのにsaveをしていたので、ここも見直しました。

③reservationテーブルのカラム名とカラムの型の見直し
timeカラムの値は時間ではなく数字の連番(ビューに記述した数字)がパラメータとして渡されてしまっていて、ここでもエラーとなってしまっていました。
カラム名をdatetimeカラムへ変更し、カラムの型もdatetimeとしました。(元々timeカラムをdatetime型としていたのですが、これもエラーの原因につながっていたと考えています)

####修正後のコード
①のコード

class CreateReservations < ActiveRecord::Migration[6.0] def change create_table :reservations do |t| t.datetime :datetime, null: false t.timestamps end end end
class Reservation < ApplicationRecord validates :datetime, presence: { message: "を選択してください"} belongs_to :product belongs_to :user end

②のコード

class ReservationsController < ApplicationController before_action :product_name, only:[:new, :create, :edit, :update] def index @reservation = Reservation.count(current_user.id) end def new @reservation = Reservation.new end def create @reservation = Reservation.new(reservation_params) unless @reservation.save render :new end end def edit end def update end def destroy end private def reservation_params params.require(:reservation).permit(:datetime, :product_id).merge(user_id: current_user.id) end def product_name @products = Product.all
.Body .Form-box = form_with model: @reservation, local: true do |f| .alert = render 'layouts/notifications' .Form-box__content = f.label :datetime, 'ご希望の日時', class: "Form-box__content__title" %span.Form-box__content__requirement 必須 = f.datetime_field :datetime, class: "Form-box__content__select" .alert - if @reservation.errors.include?(:datetime) = @reservation.errors.full_messages_for(:datetime).first .Form-box__content = f.label :product_id, 'ご希望のコース', class: "Form-box__content__title" %span.Form-box__content__requirement 必須 = f.select :product_id, @products.map { |product| [product.product_name, product.id]}, { include_blank: '選択してください' }, { class: "Form-box__content__select" } .alert - if @product.errors.include?(:product_name) = @product.errors.full_messages_for(:product_name).first .Form-box__content = f.submit '予約', class: "Form-box__button"

③のコード
①と②のコードをご参照ください。

###最後に
アソシエーションをしっかり設計し、コードへ反映できていなかったことから始まりエラーの連続でした。
回答くださったみなさま本当ありがとうございました!

投稿2020/12/30 01:57

kurumin27

総合スコア3

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

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

0

発生しているエラーメッセージですが、具体的に何がundefinec methodとなっておりますでしょうか?

NoMethodError in ReservationsController#create undefined method

undefined method 〇〇 と出ているかと思います。〇〇の部分がエラーの原因を特定するのに必要なのでご教示いただきたいです。

投稿2020/12/28 22:53

togo_mentor

総合スコア14

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

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

kurumin27

2020/12/28 22:54

ご回答ありがとうございます。 不足があり、失礼いたしました。 undefined method `product_name' for #<Reservation:0x00007fa872f65a78> Did you mean? product となっております。
togo_mentor

2020/12/28 22:58

ご回答ありがとうございます! おそらく、Reservationモデルのファイルにvalidates :product_name, presence: trueの記述があるのに同じ名前のカラムがDBに存在しないことが原因可と思います。ご確認いただけますでしょうか?
kurumin27

2020/12/28 23:56 編集

たしかにproduct_nameは、reservation(予約)テーブルに存在しないのですが、product(商品)テーブルで管理しようと考えていました。 productテーブルへ保存したproduct_nameを予約時に呼び出して予約内容をreservationテーブルへ保存しようと考えていました。 それでも、reservationテーブルにはprduct_nameは必要なのでしょうか? もし変な設計になっている箇所がありましたら、アドバイスいただけますと助かります。
togo_mentor

2020/12/29 00:04

いえ、むしろproduct_nameはproductテーブルの情報ですから、reservationテーブルには存在しなくてOKです! 今reservationテーブルはproductテーブルとアソシエーションが組まれていますので、それを利用して予約情報に紐づくproduct_nameを呼び出せるようにしましょう。 現状設計で気になる箇所ですがreservationモデルに存在する validates :product_name, presence: trueは不要かと思います。こちらのバリデーションをもし設定するのであればproductモデルに記載すべきです。 ``` class Reservation < ApplicationRecord validates :date, presence: true validates :time, presence: true validates :product_name, presence: true has_one :product belongs_to :user end ```
kurumin27

2020/12/29 01:09

アドバイスありがとうございます。 モデルの記述は以下のように変更しました。 ``` class Reservation < ApplicationRecord validates :date, presence: true validates :time, presence: true has_one :product belongs_to :user end ``` コントローラーcreateアクションの以下の記述もコメントアウトし、実行してみたところ、エラーにはならないのですが、テーブルへデータが保存されていないようです。 unless @reservation.save render :new end binding.pryで確認してみたところ、以下のようなログになっておりました。 [1] pry(#<ReservationsController>)> params.require(:reservation).permit(:date, :time, products_attributes: [:product_name, :_destroy, :id]) Unpermitted parameter: :product_name => <ActionController::Parameters {"date"=>"2021-01-07", "time"=>"3"} permitted: true> 何がいけないのでしょうか・・・
togo_mentor

2020/12/29 01:35

返信ありがとうございます! Unpermitted parameter: :product_name と出ていることから、ストロングパラメータの記述に問題がありそうですね… 関連するproductモデルを同時に保存したいのであれば ``` def create @reservation = Reservation.create(reservation_params) unless @reservation.save render :new end @reservastion.product.create(product_name: params[:product_name]) end private def reservation_params params.require(:reservation).permit(:date, :time) end ``` のように分けて書くのはいかがでしょうか?
kurumin27

2020/12/29 03:27

いただい記述試してみたのですが、やはり下記のエラーが出てしまいます。 undefined method `product_name' for #<Reservation:0x00007fc1a1e19398> Did you mean? product 他の記述方法も試してみたのですが、ダメでした・・・
togo_mentor

2020/12/29 22:54 編集

返信ありがとうございます! なるほど、では以下の記述ではいかがでしょうか? ``` def create @reservation = Reservation.create(reservation_params) product = Product.new(product_name: params[:product_name]) @reservastion.product << product end 詳しくは下記の記事に載っております。 上記にあげたもの以外にもやり方が載っているので使えそうなものを試してみてください! https://qiita.com/jnchito/items/7f41ff3df900909952db
kurumin27

2020/12/30 02:00

こちら解決しました!いろいろと調べてくださって本当にありがとうございます!
togo_mentor

2020/12/30 23:06

良かったです!こちらこそ勉強になりました!ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問