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

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

ただいまの
回答率

90.32%

  • Ruby on Rails

    7700questions

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

Railsで一度に複数モデルのデータを作成したい場合のベストプラクティス

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 859

17number

score 6

知りたいこと

RailsでのMVCの役割は以下だと認識しています。

  • Controller : ユーザーからのリクエストを受け付けて、Model や View とのやり取りをする
  • Model : Controller から呼び出され実データを処理(CRUD)する
  • View : Controller からの情報をもとに画面を生成する

単純な Model であれば特に問題ないと思うのですが、実際のデータは色んな情報が複雑に絡み合っており、データベースも正規化することで複数テーブルに情報が分散することがほとんどだと思います。

あるモデルに関するフォームから投稿することで、複数テーブルのデータを生成したいような場合、誰がどのように処理する(責務をどう持つ)のが適切なのでしょうか?

例えば、複数人が参加することのできるゲーム大会(トーナメント)があったとします。

  • ユーザーはフォーム上からトーナメントへの参加が可能
  • 運営側は特定タイミングで次予選の参加者(勝ち残り)を決定
  • 勝ち残り判定は運営側が決定する合格スコアをもとに自動計算して判定
  • 複数回のゲーム(予選)を通して勝者を決定

上記のような場合、以下のようなモデルが必要になると思います。

  • User : ユーザー情報
  • Tournament : ゲーム大会情報
  • UserTournament : ゲーム大会とユーザーの中間テーブル
  • TournamentRound : ゲーム大会の予選情報(何組がエントリしているか、合格スコアはいくつか など)
  • RoundUser : 予選参加者情報(参加しているユーザー、ユーザー毎スコア、予選パスしたか など)

このようなケースで、運営側が予選を終了(合格者を決定)する際は、TounamentRound のデータ生成(or 更新)を行うことになると思います。予選を終了、すなわち次予選を作成するので、新たに TournamentRound および RoundUser を生成したいような場合に、

  • TournamentRoundController 内で全て処理してしまうのか
  • TournamentRoundController から RoundUserController にリダイレクトして処理させるのか
  • TournamentRoundController 内で処理するが、具体的なロジックは RoundUser モデルに記述しておき、TournamentRoundController からは該当メソッドを呼び出して処理するのか

というように、やろうと思えばどこに記述しても目的は達成できるのでは、と思っています。ただ、Fat Controller になったり、処理の見通しが悪くなったり、修正時の影響範囲が広がったり、などの差が出るものと思います。

このようなケースにおいて、どうするのが良い、Rails way的にはこうすべき、このgemを使うと解決する、など皆様の知見を教えて頂けないでしょうか?そもそもの認識誤りや、おかしな事を言っているなどあれば、そちらもご指摘頂けると幸いです。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

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

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

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

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

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

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

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

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

これについては、どこでもやろうと思えば出来るというのはその通りです。

FatControllerを避けるために、モデルに処理を書こうとするとFatModel問題が発生しますし、
そもそもActiveRecordのモデルにこういう事を書こうとすると、
責任範囲があやふやになるという問題があると思います。

という事で、ActiveRecordを継承しない普通のクラスを作ってそれに任せようという事になります。
これをサービス層、サービスクラスと呼ぶ人もいます。
しかし、サービスという呼び方はあまりにも漠然とし過ぎているため、その名前は良くないのでは?という意見もあるようです。

参考になりそうな記事を紹介しますので、こちらもご参照ください。

俺が悪かった。素直に間違いを認めるから、もうサービスクラスとか作るのは止めてくれ - Qiita
サービスクラスについては僕も悪かったと思っているけど、それでもCQSは実現したいんだ - Qiita

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/02/27 11:53

    mingosさん、回答いただき、ありがとうございます。いただいたコメントの通り、Fat Controller, Fat Model や責任範囲の分散(曖昧化)が気になるところです。

    mingosさんの言われているように、サービスクラスなど色んなクラス(Validator とか Decorator とか)を作って責務を明確化するべき、という話は目にしてきました。今回、ご紹介いただいた記事は以前に見たことはあるのですが、その時にはRailsを触っておらず、サービスクラスの必要性や役割などを実感を持って見れておりませんでした。(Feedly や Mohikan slack で色んな技術記事は眺めるようにしていたので、記事を見たことがありました。)

    いま見ると本当の意味で理解できるかと思うので、あらためて確認・熟読してみようと思います。ありがとうございます。

    他の方もご意見がありましたら、コメント頂けると幸いです。

    キャンセル

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

  • ただいまの回答率 90.32%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

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

  • Ruby on Rails

    7700questions

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