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

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

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

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

Ruby on Rails

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

受付中

フォームオブジェクトで、複数のモデルが絡むバリデーションを行いたい

zendendo
zendendo

総合スコア0

Ruby

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

Ruby on Rails

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

0回答

0評価

0クリップ

3閲覧

投稿2017/12/12 00:56

編集2022/01/12 10:55

###前提・実現したいこと
ruby(ruby on rails)で、単一ポイントの取引機能(振込機能)があり、
支払ユーザーが保有する口座の残高を超える取引額を不可にしたい(支払ユーザーの口座残高未満の取引額ならモデルに保存・更新したい)と考えています。

ただし、残高を記録しているモデルと取引額を記録しているモデルは別々になっています。

いわゆる複数のモデルが絡むバリデーションになると思うのですが、そうゆう場合は、フォームオブジェクトで設定した方がいいと聞き、
フォームオブジェクトを作成してみたのですが、
よくわからず、うまくいかず困っています。

現状では、入力フォームで「支払先の口座番号」と「取引額」を入力すると、
3つのモデルが同時に動くようになっています。
図にするとこんな感じです。
イメージ説明
イメージ説明
例えば、支払ユーザーの口座残高が10000(1万)なら、1万を超える数値の入力を
AmmountTransaction(取引)モデルのamount(取引額)、
DepositsAndwithdrawal(入出金)モデルのamount(取引額)、
BasicIncomeAccount(口座)モデルのbalance(残高)を更新する際に使う増減額、
で禁止(バリデーション)できるようにしたいのですが、
その場合、formオブジェクトやコントローラ等のファイルには、どんな記述をすれば
いいのでしょうか?

教えて頂ければ幸いです。

###試しに書いたソースコード

フォームオブジェクトのコードになります。
app/models/form/account_transaction_form.rb

ruby

class AccountTransactionForm include ActiveModel::Model attr_accessor :erroes, :amount, :deposit_account_id def initialize(amount, withdrawal_account_id, deposit_account_id, basic_income_account) @amount = amount @withdrawal_account_id = withdrawal_account_id @deposit_account_id = deposit_account_id @balance = basic_income_acccount.balance @errors = ActiveModel::Errors.new(self) end #検証に関する記述 def valid? errors.clear if @balance < @amount errors.add(:amount, "残高以上の送金はできません") end errors.empty? end end

コントローラのコードです。3つのモデルを動かす取引処理の記述が書かれています。
取引処理は複数のモデルが絡む固有の処理(ビジネスロジックというもの?)なので、
この固有の処理もフォームオブジェクトやサービスクラスに
移動させた方がいいのですが、ひとまずおいておきます。
コントローラには、フォームオブジェクトを呼び出す記述をすると思うのですが、
仮に複数のモデルが絡むバリデーションだけを行うフォームオブジェクトの場合、
どこにどんな記述をすればいいのでしょうか?

ruby

class AccountTransactionsController < ApplicationController #取引を作成する def new @account_transaction = AccountTransaction.new end #取引処理をする為に3つのモデルを同時に保存・更新している def create #取引モデルに1件のレコードを新規作成 AccountTransaction.transaction do @account_transaction = AccountTransaction.new( withdrawal_account_id: current_user.basic_income_account.id, deposit_account_id: BasicIncomeAccount.find_by(account_number: params[:account_transaction][:deposit_account_id]).id, amount: params[:account_transaction][:amount] ) @account_transaction.save! #入出金モデルに2件のレコードを新規作成 DepositsAndWithdrawal.transaction do #出金側レコードを作成保存 @account_transaction.deposits_and_withdrawals.build( transaction_type: "出金", basic_income_account_id: current_user.basic_income_account.id, amount: -1 * params[:account_transaction][:amount].to_f ) @account_transaction.save! #出金側レコードを作成保存 @account_transaction.deposits_and_withdrawals.build( transaction_type: "入金", basic_income_account_id: BasicIncomeAccount.find_by(account_number: params[:account_transaction][:deposit_account_id]).id, amount: params[:account_transaction][:amount].to_f ) @account_transaction.save! #口座モデルを更新(残高の増減) BasicIncomeAccount.transaction do @withdrawal_basic_income_account = current_user.basic_income_account @deposit_basic_income_account = BasicIncomeAccount.find_by(account_number: params[:account_transaction][:deposit_account_id]) @withdrawal_amount = params[:account_transaction][:amount].to_f @deposit_amount = params[:account_transaction][:amount].to_f @withdrawal_basic_income_account.update(balance: @withdrawal_basic_income_account.balance - @withdrawal_amount) @deposit_basic_income_account.update(balance: @deposit_basic_income_account.balance + @deposit_amount) end end end redirect_to root_path rescue => e render plain: e.message end private def account_transaction_params params.require(:account_transaction).permit(:deposit_account_id, :amount) end end

入力フォーム画面のコードです。

<%= 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.label :送金額 %> <%= f.number_field :amount,min:1,max:999999999999999 %> <%= f.submit"送金確認" %> </div> <% end %>

3つのモデルの状態です。

create_table "account_transactions", force: :cascade do |t| t.decimal "amount" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "withdrawal_account_id" t.integer "deposit_account_id" t.index ["deposit_account_id"], name: "index_account_transactions_on_deposit_account_id" t.index ["withdrawal_account_id"], name: "index_account_transactions_on_withdrawal_account_id" end create_table "basic_income_accounts", force: :cascade do |t| t.integer "user_id" t.string "account_number" t.decimal "balance" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["user_id"], name: "index_basic_income_accounts_on_user_id" end create_table "deposits_and_withdrawals", force: :cascade do |t| t.integer "account_transaction_id" t.string "transaction_type" t.decimal "amount" t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "basic_income_account_id" t.index ["account_transaction_id"], name: "index_deposits_and_withdrawals_on_account_transaction_id" t.index ["basic_income_account_id"], name: "index_deposits_and_withdrawals_on_basic_income_account_id" end

###補足情報(言語/FW/ツール等のバージョンなど)
Rails 5.1.3
ruby 2.4.1
devise (4.3.0)

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

まだ回答がついていません

会員登録して回答してみよう

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Ruby

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

Ruby on Rails

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