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

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

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

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

Ruby

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

Q&A

解決済

2回答

5489閲覧

親モデルと同時に子モデルに複数のレコードを作成したい

zendendo

総合スコア43

Ruby on Rails 5

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

Ruby

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

0グッド

0クリップ

投稿2017/11/29 08:56

編集2017/12/02 23:48

###前提・実現したいこと
ruby on railsで、取引アカウント同士の取引記録を実装しています。

入力フォームで、ユーザーが「取引相手の口座番号」と「取引額」の2項目を入力するだけで、
取引モデル(親モデル)で1件のレコードが作成されると同時に、
1:多として関連付けを施してある入出金モデル(子モデル)に複数のレコードを自動的に作成したい
と思っています。
作成するレコードは、
「出金(支払)」のレコードと
「入金(受取)」のレコードの2件です。
図にするとこんな感じです。
![イメージ説明

これを実現しようとしたのですが2点ほど問題が発生して困っています。
1つ目は、
undefined method `transaction_type=' for #DepositsAndWithdrawal::ActiveRecord_Associations_CollectionProxy:0x007f189cc329c0
というエラーが発生してしまって困っています。

2つ目は、入出金モデルの出金レコードの取引カラムの数値をマイナス数値として記録されないことに、
困っています。(入力フォームから渡されたパラメータの数値をマイナス数値に変換する方法がわからなくて困っています)

どうすれば、これらの問題を解消できるか教えて頂ければ幸いです。よろしくお願いします。

以下が現状のコードになります。
###現状のコード
AccountTransaction(取引)モデルは、多数のdeposits_and_withdrawals(入出金)モデルを持つという
1:多の関連付けを施してあります。

ruby

1class AccountTransaction < ApplicationRecord 2 3 belongs_to :withdrawal, class_name: 'BasicIncomeAccount', :foreign_key => 'withdrawal_account_id' 4 belongs_to :deposit, class_name: 'BasicIncomeAccount', :foreign_key => 'deposit_account_id' 5#取引モデルは、入出金モデルを多数保有している 6 has_many :deposits_and_withdrawals 7 8end

ruby

1class DepositsAndWithdrawal < ApplicationRecord 2#入出金モデルは、一つの取引モデルに保有されている 3 belongs_to :account_transaction 4 5 belongs_to :basic_income_account 6 7end 8

取引入力画面です。
app/views/account_transactions.html.erb

<%= form_for @account_transaction do |f|%> <% if @account_transaction.errors.any? %> <h3>入力内容にエラーが<%= @account_transaction.errors.count %>件あります</h3> <ul> <% @account_transaction.errors.full_messages.each do |message| %> <li><%= message %></li> <% end %> </ul> <% end %> <div class="field"> <%= f.label :送金相手の口座番号 %> <%= f.text_field :deposit_account_id %> <%# <%= f.number_field :deposit_account_id %> <%= f.label :送金額 %> <%= f.number_field :amount %>  <%= f.submit"送金確認" %> </div> <div> <%= @account_transaction.errors.to_yaml %> </div> <% end %>

AccountTransactionのコントローラには、取引モデルへの記録と同時に、
入出金モデルにもレコードを作成するようにbuildメソッドを使い以下のように記述をしました。
しかし、
入力フォームで、取引を入力してsubmitボタンを押すと、
NoMethodError in AccountTransactionsController#create
undefined method `transaction_type=' for #DepositsAndWithdrawal::ActiveRecord_Associations_CollectionProxy:0x007f189cc329c0
というエラーになってしまいます。

ruby

1class AccountTransactionsController < ApplicationController 2 3 def create 4#以下5行のコードは、取引モデルに記録するためのコード 5 @account_transaction = AccountTransaction.new( 6 withdrawal_account_id: current_user.basic_income_account.id, 7 deposit_account_id: BasicIncomeAccount.find_by(account_number: params[:account_transaction][:deposit_account_id]).id, 8 amount: params[:account_transaction][:amount] 9 ) 10 ##取引モデルのレコード作成と同時に入出金モデルにも関連付けしたレコードを作成する為のコード 11  #以下5行は出金側のレコードを作成する 12 @account_transaction.deposits_and_withdrawals.build 13 @account_transaction.deposits_and_withdrawals.transaction_type = '出金' 14 @account_transaction.deposits_and_withdrawals.basic_income_account_id = current_user.basic_income_account.id 15 @account_transaction.deposits_and_withdrawals.amount = -params[:account_transaction][:amount]#ここの渡された数値をマイナス数値にしたい 16 @account_transaction.save 17  #以下5行は入金側のレコードを作成する 18 @account_transaction.deposits_and_withdrawals.build 19 @account_transaction.deposits_and_withdrawals.transaction_type = "入金" 20 @account_transaction.deposits_and_withdrawals.basic_income_account_id = BasicIncomeAccount.find_by(account_number: params[:account_transaction][:deposit_account_id]).id 21 @account_transaction.deposits_and_withdrawals.amount = params[:account_transaction][:amount] 22 @account_transaction.save 23 24###@account_transactionを保存し、保存できたらホーム画面(root_path)へ、失敗なら取引入力画面(new)へ飛ぶ。 25 if @account_transaction.save 26 redirect_to root_path 27 else 28 render "new" 29 end 30 end 31 32 def account_transaction_params 33 params.require(:account_transaction).permit(:deposit_account_id, :amount) 34 end 35end

ここまで読んでいただきありがとうございました。
もし、足りない部分を指摘して頂ければ追記します。

###補足情報(言語/FW/ツール等のバージョンなど)
Rails 5.1.3
ruby 2.4.1
###追記:アドバイスを受けて修正したコード

AccountTransactionのコントローラファイル。

ruby

1class AccountTransactionsController < ApplicationController 2 3 4 #取引を作成する 5 def new 6 @account_transaction = AccountTransaction.new 7 end 8 9 #取引を作成して記録する 10 def create 11 @account_transaction = AccountTransaction.new( 12 withdrawal_account_id: current_user.basic_income_account.id, 13 deposit_account_id: BasicIncomeAccount.find_by(account_number: params[:account_transaction][:deposit_account_id]).id, 14 amount: params[:account_transaction][:amount] 15 ) 16#####################修正中箇所############################# 17 #出金側 18 @deposits_and_withdrawal1 = DepositsAndWithdrawal.new 19 @deposits_and_withdrawal1.transaction_type = '出金' 20 @deposits_and_withdrawal1.basic_income_account_id = current_user.basic_income_account.id 21 @deposits_and_withdrawal1.amount = -1 * params[:account_transaction][:amount].to_f 22 @account_transaction.deposits_and_withdrawals << @deposits_and_withdrawal1 23 24 #入金側 25 @deposits_and_withdrawal2 = DepositsAndWithdrawal.new 26 @deposits_and_withdrawal2.transaction_type = '出金' 27 @deposits_and_withdrawal2.basic_income_account_id = BasicIncomeAccount.find_by(account_number: params[:account_transaction][:deposit_account_id]).id, 28 @deposits_and_withdrawal2.amount = params[:account_transaction][:amount] 29 @account_transaction.deposits_and_withdrawals << @deposits_and_withdrawal2 30#################修正中箇所はここまで###################### 31###@account_transactionを保存し、保存できたらホーム画面(root_path)へ、失敗なら取引入力画面(new)へ飛ぶ。 32 if @account_transaction.save 33 redirect_to root_path 34 else 35 render "new" 36 end 37 end 38 39 def account_transaction_params 40 params.require(:account_transaction).permit(:deposit_account_id, :amount) 41 end 42end

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

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

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

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

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

guest

回答2

0

自己解決

ひとまず、以下のコードで解決することができました。

解決策をまとめると、1つのレコードを作成するごとにsaveを記述することで解決しました。
イメージ説明

まずは、AccountTransaction(取引)モデルにレコードを作成して保存(save)。
その後、関連付けで子モデルにレコードを作成するbuildメソッドを使い、まずは出金レコードを作成して保存(save)。
ちなみに、1:多の関連付けでレコードを作成する場合は、
@変数.複数系モデル名.build()
とするみたいです。
今回の場合、子モデルであるDepositsAndWithdrawal(入出金)モデルにも作成したいので、
@account_transaction.deposits_and_withdrawals.build
となります。
同じく入金側レコードも、関連付けで子モデルにレコードを作成するbuildメソッドを使って保存(save)。

account_transactions_contoroller.rb

ruby

1class AccountTransactionsController < ApplicationController 2 3 #取引を作成する 4 def new 5 @account_transaction = AccountTransaction.new 6 end 7 8 #取引を作成して記録する 9 def create 10 #以下5行のコードで取引モデル(親モデル)への記録を行う 11 @account_transaction = AccountTransaction.new( 12 withdrawal_account_id: current_user.basic_income_account.id, 13 deposit_account_id: BasicIncomeAccount.find_by(account_number: params[:account_transaction][:deposit_account_id]).id, 14 amount: params[:account_transaction][:amount] 15 ) 16 @account_transaction.save#親モデル(取引モデル)へレコードを作成保存する 17 18 #以下6行では取引テーブルと関連付けした入出金テーブル(子モデル)に出金レコードを作成する 19 @account_transaction.deposits_and_withdrawals.build( 20 transaction_type: "出金", 21 basic_income_account_id: current_user.basic_income_account.id, 22 amount: -1 * params[:account_transaction][:amount].to_f#マイナス小数点ありの数値化 23 ) 24 @account_transaction.save#子モデル(入出金モデル)に出金側レコードを保存する 25 26 #以下5行では取引テーブルと関連付けした入出金テーブルに入金レコードを作成する 27 @account_transaction.deposits_and_withdrawals.build( 28 transaction_type: "入金", 29 basic_income_account_id: BasicIncomeAccount.find_by(account_number: params[:account_transaction][:deposit_account_id]).id, 30 amount: params[:account_transaction][:amount].to_f 31 ) 32#@account_transactionを保存し、保存できたらホーム画面(root_path)へ、失敗なら取引入力画面(new)へ飛ぶ。 33 if @account_transaction.save# 34 redirect_to root_path 35 else 36 render "new" 37 end 38 end 39 40 private 41 def account_transaction_params 42 params.require(:account_transaction).permit(:deposit_account_id, :amount) 43 end 44end

一応これで当初達成したかった「親モデルと同時に子モデルに複数のレコードを作成したい」を実行できます。

投稿2017/12/02 23:43

編集2017/12/02 23:52
zendendo

総合スコア43

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

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

0

Ruby

1 #以下5行は出金側のレコードを作成する 2 @deposits_and_withdrawal1 = DepositsAndWithdrawal.new 3 @deposits_and_withdrawal1.transaction_type = '出金' 4 @deposits_and_withdrawal1.basic_income_account_id = current_user.basic_income_account.id 5 @deposits_and_withdrawal1.amount = -1 * params[:account_transaction][:amount]#ここの渡された数値をマイナス数値にしたい 6 @account_transaction.deposits_and_withdrawals << @deposits_and_withdrawal1 7 8 ... 9 入金側も同様 10 ... 11 12 # ここですべて同時に保存される 13 @account_transaction.save

投稿2017/11/29 21:16

Takahito_Ogawa

総合スコア229

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

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

zendendo

2017/11/30 01:58 編集

Takahito_Ogawaさん、回答ありがとうございます! アドバイスを元に、account_transactions_controller.rbの コードを修正してみました。(修正したコードが長くコメント欄では見ずらいので、質問文に追記してあります) エラーは特に表示されてはいないのですが、 保存に失敗したようで、テーブルには何も保存されませんでした。
Takahito_Ogawa

2017/11/30 12:49

save実行時のログを見せてもらってもよろしいでしょうか。
zendendo

2017/11/30 23:40

以下が、save時のログになります。 Started POST "/account_transactions" for 10.0.2.2 at 2017-11-30 23:38:53 +0000 Cannot render console from 10.0.2.2! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255 Processing by AccountTransactionsController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"BrhH+NkieKuNcWzUVA0nt7ni3L7xNImb54Jvi2Zhn+UbgEEkjWGT974g7Iqn0fiGeERi7Mjhhpx5nUjkeiF52g==", "account_transaction"=>{"deposit_account_id"=>"454839067625", "amount"=>"2525"}, "commit"=>"送金確認"} User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 20], ["LIMIT", 1]] BasicIncomeAccount Load (0.2ms) SELECT "basic_income_accounts".* FROM "basic_income_accounts" WHERE "basic_income_accounts"."user_id" = ? LIMIT ? [["user_id", 20], ["LIMIT", 1]] BasicIncomeAccount Load (0.1ms) SELECT "basic_income_accounts".* FROM "basic_income_accounts" WHERE "basic_income_accounts"."account_number" = ? LIMIT ? [["account_number", "454839067625"], ["LIMIT", 1]] (0.1ms) begin transaction BasicIncomeAccount Load (0.2ms) SELECT "basic_income_accounts".* FROM "basic_income_accounts" WHERE "basic_income_accounts"."id" = ? LIMIT ? [["id", 19], ["LIMIT", 1]] BasicIncomeAccount Load (0.1ms) SELECT "basic_income_accounts".* FROM "basic_income_accounts" WHERE "basic_income_accounts"."id" = ? LIMIT ? [["id", 18], ["LIMIT", 1]] SQL (0.7ms) INSERT INTO "account_transactions" ("amount", "created_at", "updated_at", "withdrawal_account_id", "deposit_account_id") VALUES (?, ?, ?, ?, ?) [["amount", 2525.0], ["created_at", "2017-11-30 23:38:53.745727"], ["updated_at", "2017-11-30 23:38:53.745727"], ["withdrawal_account_id", 19], ["deposit_account_id", 18]] (175.6ms) commit transaction (0.1ms) begin transaction BasicIncomeAccount Load (0.3ms) SELECT "basic_income_accounts".* FROM "basic_income_accounts" WHERE "basic_income_accounts"."id" = ? LIMIT ? [["id", 19], ["LIMIT", 1]] SQL (0.6ms) INSERT INTO "deposits_and_withdrawals" ("account_transaction_id", "transaction_type", "amount", "created_at", "updated_at", "basic_income_account_id") VALUES (?, ?, ?, ?, ?, ?) [["account_transaction_id", 24], ["transaction_type", "出金"], ["amount", -2525.0], ["created_at", "2017-11-30 23:38:53.929085"], ["updated_at", "2017-11-30 23:38:53.929085"], ["basic_income_account_id", 19]] (7.1ms) commit transaction BasicIncomeAccount Load (0.2ms) SELECT "basic_income_accounts".* FROM "basic_income_accounts" WHERE "basic_income_accounts"."account_number" = ? LIMIT ? [["account_number", "454839067625"], ["LIMIT", 1]] (0.3ms) begin transaction (0.1ms) commit transaction (0.1ms) begin transaction (0.1ms) rollback transaction Rendering account_transactions/new.html.erb within layouts/application Rendered account_transactions/new.html.erb within layouts/application (4.4ms) Rendered layouts/_shim.html.erb (0.4ms) Rendered layouts/_header.html.erb (2.0ms) Rendered layouts/_footer.html.erb (0.5ms) Completed 200 OK in 265ms (Views: 52.3ms | ActiveRecord: 186.0ms)
Takahito_Ogawa

2017/12/01 02:03

ありがとうございます。ログを注意深く確認しましたが、どうもsaveが3回実行されているようです。意図した動作と異なるので、前のコードのまま実行して、そのログを表示してしまっているのではないかと疑っているのですが、ご確認いただけませんでしょうか。
zendendo

2017/12/01 12:12 編集

申し訳ありません。ご指摘の通り、余分なsaveを残したまま実行をしていました。 以下は余分なsaveを削ったログになります。 Started POST "/account_transactions" for 10.0.2.2 at 2017-12-01 10:29:37 +0000 Cannot render console from 10.0.2.2! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255 Processing by AccountTransactionsController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"chnC9+Td0RGG5Cox95mXbWvhP8khfGt4xMMtgPejmnxJ5WgqkH2lyvhrhgMNtYas6XzG7F10GKCkfmLxjLdJTA==", "account_transaction"=>{"deposit_account_id"=>"454839067625", "amount"=>"2828"}, "commit"=>"送金確認"} User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT ? [["id", 20], ["LIMIT", 1]] BasicIncomeAccount Load (0.2ms) SELECT "basic_income_accounts".* FROM "basic_income_accounts" WHERE "basic_income_accounts"."user_id" = ? LIMIT ? [["user_id", 20], ["LIMIT", 1]] BasicIncomeAccount Load (0.2ms) SELECT "basic_income_accounts".* FROM "basic_income_accounts" WHERE "basic_income_accounts"."account_number" = ? LIMIT ? [["account_number", "454839067625"], ["LIMIT", 1]] CACHE BasicIncomeAccount Load (0.0ms) SELECT "basic_income_accounts".* FROM "basic_income_accounts" WHERE "basic_income_accounts"."account_number" = ? LIMIT ? [["account_number", "454839067625"], ["LIMIT", 1]] (0.2ms) begin transaction BasicIncomeAccount Load (0.1ms) SELECT "basic_income_accounts".* FROM "basic_income_accounts" WHERE "basic_income_accounts"."id" = ? LIMIT ? [["id", 19], ["LIMIT", 1]] BasicIncomeAccount Load (0.2ms) SELECT "basic_income_accounts".* FROM "basic_income_accounts" WHERE "basic_income_accounts"."id" = ? LIMIT ? [["id", 18], ["LIMIT", 1]] CACHE BasicIncomeAccount Load (0.0ms) SELECT "basic_income_accounts".* FROM "basic_income_accounts" WHERE "basic_income_accounts"."id" = ? LIMIT ? [["id", 19], ["LIMIT", 1]] (0.1ms) rollback transaction Rendering account_transactions/new.html.erb within layouts/application Rendered account_transactions/new.html.erb within layouts/application (3.1ms) Rendered layouts/_shim.html.erb (0.3ms) Rendered layouts/_header.html.erb (1.0ms) Rendered layouts/_footer.html.erb (0.4ms) Completed 200 OK in 58ms (Views: 39.2ms | ActiveRecord: 1.4ms)
Takahito_Ogawa

2017/12/01 12:54

ありがとうございます。save失敗後のnew.html.erbに、@account_transaction.errors.to_yamlをdiv要素に入れて表示してもえますか? エラーメッセージが出るはずです。
zendendo

2017/12/01 13:18 編集

度々ありがとうございます。 以下の内容がsave失敗後の入力フォーム画面に表示されたエラーになります。 ・Deposits and withdrawals is invalid --- !ruby/object:ActiveModel::Errors base: !ruby/object:AccountTransaction concise_attributes: - !ruby/object:ActiveRecord::Attribute::FromDatabase name: id - !ruby/object:ActiveRecord::Attribute::FromUser name: amount value_before_type_cast: '256' original_attribute: !ruby/object:ActiveRecord::Attribute::FromDatabase name: amount type: !ruby/object:ActiveModel::Type::Decimal precision: scale: limit: - !ruby/object:ActiveRecord::Attribute::FromDatabase name: created_at - !ruby/object:ActiveRecord::Attribute::FromDatabase name: updated_at - !ruby/object:ActiveRecord::Attribute::FromUser name: withdrawal_account_id value_before_type_cast: 19 original_attribute: !ruby/object:ActiveRecord::Attribute::FromDatabase name: withdrawal_account_id type: &1 !ruby/object:ActiveModel::Type::Integer precision: scale: limit: range: !ruby/range begin: -2147483648 end: 2147483648 excl: true - !ruby/object:ActiveRecord::Attribute::FromUser name: deposit_account_id value_before_type_cast: 18 original_attribute: !ruby/object:ActiveRecord::Attribute::FromDatabase name: deposit_account_id type: *1 new_record: true active_record_yaml_version: 2 messages: :deposits_and_withdrawals: - is invalid :送金相手の口座番号: [] :deposit_account_id: [] :送金額: [] :amount: [] details: :deposits_and_withdrawals: - :error: :invalid - :error: :invalid
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問