前提・実現したいこと
楽曲の情報を登録するアプリを作っています。任意の楽曲の演奏時間を登録する機能を実装しようとしています。曲は複数の楽章から構成されます。
その際に入力した分と秒を楽章別に計算して秒に変換し、DBに登録したいです。form_withとfields_forを使います。
発生している問題・エラーメッセージ
曲の情報は親モデル(Post)、演奏そのものの情報は子モデル(Recording)、演奏時間の情報は孫モデル(Duration)の管轄です。
子モデルのフォームで分(min)と秒(sec)を登録し、それらを計算して秒(duration)に変換して、なおかつそれを孫モデルに格納する流れがわかりません。どうすればよいでしょうか。
Started POST "/posts/2/recordings" for ::1 Processing by RecordingsController#create as JS Parameters: {"authenticity_token"=>"N3NSB14zOEEgMKWfWwtVxnHN3PCyNpO6zwJHuSiadQvOfHTeP9RBofItGZeWDPc407Z/HyfSXpCDnt7q KSWHQw==", "recording"=>{"composer"=>"Mozart", "title"=>"Symphony No.40", "conductor"=>"test", "orchestra"=>"test", "durations_attributes"=>{ "0"=>{"mov"=>"1", "min"=>"1", "sec"=>"1"}, "1"=>{"mov"=>"2", "min"=>"2", "sec"=>"2"}, "2"=>{"mov"=>"3", "min"=>"3", "sec"=>"3"}, "3"=>{"mov"=>"4", "min"=>"4", "sec"=>"4"} }, "year"=>"2000", "label"=>"test", "review"=>"test", "post_id"=>"2"}, "commit"=>"Create", "post_id"=>"2"} Completed 500 Internal Server Error in 4ms (ActiveRecord: 0.0ms | Allocations: 3104) NoMethodError (undefined method `set_duration' for nil:NilClass): app/controllers/recordings_controller.rb:19:in `recording_params_with_duration' app/controllers/recordings_controller.rb:12:in `create'
該当のソースコード
Ruby
1 2コントローラ(Recording) 3class RecordingsController < ApplicationController 4 5 def index 6 end 7 8 def new 9 @recording = Post.find(params[:post_id]).recordings.new 10 @recording.durations.build 11 end 12 13 def create 14 @recording = Recording.new(recording_params_with_duration) 15 @recording.save 16 redirect_to('/posts/') 17 end 18 19 def recording_params_with_duration 20 recording_params.reverse_merge(@durations.set_duration) 21 end 22 23 def recording_params 24 params.require(:recording).permit( 25 (中略) 26 durations_attributes: [:mov, :min, :sec, :duration] 27 ) 28 end 29 30コントローラ(duration) 31class DurationsController < ApplicationController 32 33end 34 35 36 37モデル 38 39Post(親モデル) 40class Post < ApplicationRecord 41 has_many :recordings 42 has_many :post_instruments 43 has_many :instruments, :through => :post_instruments 44 accepts_nested_attributes_for :recordings, {allow_destroy: true} 45end 46 47Recording(子モデル) 48class Recording < ApplicationRecord 49 belongs_to :post 50 has_many :durations 51 accepts_nested_attributes_for :durations 52end 53 54Duration(孫モデル) 55class Duration < ApplicationRecord 56 belongs_to :recording 57 58 def duration 59 min * 60 + sec 60 end 61 62 def set_duration 63 {:duration => duration } 64 end 65end 66 67 68ビュー 69<%= form_with model: @recording, url: post_recordings_path do |f| %> 70 71 <% for i in 1..@recording.post.mov do %> 72 <%= f.fields_for :durations do |dur| %> 73 <%= dur.number_field :mov, value: "#{i}" %><br> 74 <%= dur.label :"mov#{i}min" %> 75 <%= dur.number_field :min, min: 0 %><br> 76 <%= dur.label :"mov#{i}sec" %> 77 <%= dur.number_field :sec, min: 0, max: 59 %><br> 78 <% end %> 79 <% end %> 80 81データベース 82 83CREATE TABLE IF NOT EXISTS "recordings" ("id" integer NOT NULL PRIMARY KEY, (中略)CONSTRAINT "fk_rails_47949a0700" 84FOREIGN KEY ("post_id") 85 REFERENCES "posts" ("id") 86CREATE TABLE IF NOT EXISTS "durations" ("id" integer NOT NULL PRIMARY KEY,"min" integer DEFAULT NULL, "sec" integer DEFAULT NULL, "mov" integer DEFAULT NULL, "recording_id" integer DEFAULT NULL, "duration" integer, CONSTRAINT "fk_rails_4bba954102" 87FOREIGN KEY ("recording_id") 88 REFERENCES "recordings" ("id") 89
試したこと
マージを使ってパラメータをマージさせる方法を載せているウェブサイト、あるいは計算をする方法を載せているウェブサイトは複数あり、それを模倣してやってみました(例:https://qiita.com/miyzawa/items/18bb8d88ad004cbc439c)。しかしそれは同一モデル内での話で、親子モデル間でそれをすることができませんでした。
コントローラやモデルにおけるメソッドの間の受け渡しについての理解が足りないのではないかと思っております
補足情報(FW/ツールのバージョンなど)
回答3件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。