【第29週】パRails輪読会🚂 (2024-03-04~ 2024-03-15)

tags: パRails🚂

目次


2024-03-04(月)

ファシリ

@motohiro-mm

ドライバー

読んだところ

11-3-4 473p コラム「サービスオブジェクトの実装ルールやインターフェースについて」から
PR:

次回

476P 12-2 「データベースと紐づかないモデルを作る」から 🚂

学んだこと・感想

  • @sharoa

    • サービスオブジェクトを導入、運用していくにあたって、その実装ルールやインターフェースを決めることはとても重要。
    • サービスオブジェクトを実装するクラスの命名も大事で、ある1つのドメインロジックを指すものにすると良いらしい。
    • そしてこのロジックを実行するためのクラスメソッドを一つだけ公開するようにしましょう、とのこと。(各サービスオブジェクトに何を実装すべきかが明らかになるため。)
    • サラッと12章に突入したw
    • ユースケースとは、、、なんらかの目的を達成するために行われるユーザーとアプリケーション間の一連のやり取りを表したもの。(例:Xのアカウントでログインする、など。)
    • 12-1-3や12-1-4はとにかくふむふむでした。次でその対処を教えてくれるらしいので、それを楽しみ(?)にしておきます。
  • @sugiwe

    • そういえば金曜日お休みしたんだった😇サービスオブジェクトのことがさっぱりなので、復習します!
    • ユースケース
      • アプリケーションにおけるイチ機能(GitHubログイン機能、イベント登録機能、など)
    • ユーザとアプリケーションの間のやりとり
      • 1つのユースケースに含まれる1つor複数のCRUD操作(登録ページをgetしてイベント内容をpostして完成したイベントページをgetする、みたいな?)
    • 上記のような感じ?ざっくりわかったようなわからないような…
    • まずはFat Controllerを防ぐように意識する、というのが初心者向けの心得としてあったが、アプリケーションが複雑になってくるとFat Modelになってくるので、それをさらに対処する必要が出てくると。中級者向けの内容だなぁと感じた…!
  • @shodan

    • たくさんの事柄が絡む複雑なアプリを作りたいとおもったときに試されるのは、Railsの使い方というよりはオブジェクト思考的な設計とかそういうことな気がする。
    • 上の知識があったときに、それを簡単に実現してくれるRailsや周辺のgemが提供する各種APIの凄さに驚く、みたいな感じなのかなと想像。
    • Railsで初めてプログラミングを学ぶ層には逆にハードな話なのかな〜と思ったりする。
  • @sadanora

    • サービスオブジェクトのクラス名はひとつのドメインロジックを指す具体的ものにする。
    • Module#private_class_method
      • 指定したクラスメソッドをprivateにする
    • Railsはドメインロジックとユースケースのロジックという異なるロジックをモデルに実装できる
      • これによって高い生産性を実現している反面、アプリケーションへの機能要求が複雑になると立ち行かなくなるので工夫が必要になる。
  • @moegi29

    • サービスオブジェクトのクラス名には決まった命名規則が存在しないのでプロジェクトやチーム内で決める必要があるっぽい。
    • アプリ開発におけるユースケース→何らかの目的を達成するために行われるユーザとアプリ間のやり取りを表したもの
    • Railsにおけるユースケース→URLで表されるリソースをDBのテーブルと対応させていてCRUD操作でユーザとやり取りすることを指している
    • 今日も抽象度が高い話が多くてなかなか理解が難しかったです、もう一度復習しておきます
  • @motohiro-mm

    • サービスオブジェクトはよく考えて導入する(ルールとか。以下例)
      • クラス名をある1つのドメインロジックを指すものにする
      • 公開するクラスメソッドは1つだけにする(今回はself.call
      • クラスの外からインスタンスを生成できないようにする(private_class_method :new
    • ユースケース:「イベントを登録する」とか
      • Railsでは1つor複数のCRUD操作によって1つのユースケースが構成される
    • Railsのモデルは、ドメインロジックとユースケースのロジック(主にバリデーションやコールバック)を実装できる
      • から高い生産性を実現している(らしい)
      • がFatModelになるリスクがある
  • @sakanobu

    • 2つのロジックをモデルに集めるのが Rails のアプローチ
      • アプリケーションが対象とする問題領域のロジック (ドメインロジック?)
        • インスタンスメソッド
          • リスト11.11 BankAccountMoneyTransfer の transfer_money メソッドとか?
          • クラスメソッドはどう分類されるんだろう?
            • shodanさんやsadanoraさんより、そもそもモデルのクラスメソッドには scope メソッドで名付けがちなテーブル内のある条件に該当するインスタンスを持ってくるクエリ的なものが実装されるとのこと
              • 下記のソースコードの recently_campaign クラスメソッドは直近の campaign を取得するというもので、(CRUD の READ にあたりそう、)ユースケースで表すなら「ユーザーが直近の campaign を閲覧する」となるっぽいことから推測するにユースケースじゃなくてドメインロジック寄りだと感じた
              • ソースコード:bootcamp/app/models/campaign.rb at main · fjordllc/bootcamp:
      • ユーザーとアプリケーションの間のやり取りに関するロジック (ユースケースのロジック?)
        • バリデーション
          • ただし、モデル専用のバリデーションもあるのでユースケースにしかバリデーションを書かないという意味ではない
        • コールバック
    • 「ユーザー登録完了後にウェルカムメールを送信する」という場合の「メール送信」は、やろうと思えば UserController の create アクション内で user.save の次の行あたりベタ書きすることも出来るが、Rails の基本的なアプローチは User モデル内で after_create :<メール送信用の private メソッド名> などのように実装する、つまり、モデルにユースケースのロジックを集めていくということに気をつける
      • しかし、色々な URL から User モデルに導線が集中するとユースケースのロジックを if や on で上手く場合分けしなければならなくなるわけで、それは辛いモデルの肥大化だそう
        • 基本的に Fat Controller よりも Fat Model を目指すべきだが、「良い(仕方ない?) Fat Model」と「悪い Fat Model」があるってこと?その肥大化を解体する術をこれからのページで学べるのは楽しみ

※3月の第1週は4日のみの活動となったため、第2週目もこちらに記載します。


2024-03-11(月)

ファシリ

@moegi29

ドライバー

読んだところ

476P 12-2 「データベースと紐づかないモデルを作る」から
12-2-2 「ActiveModelとは」の途中まで。
PR:

次回

481p 「🔳 ActiveModel::Validations」から。🚂

学んだこと・感想

  • @sharoa

    • ユースケースってなんだっけ?というところから始まりましたが、なんとなく思い出せて話が進められたかな、と思います。
    • ユースケースのロジックを実装するレイヤーを導入する方法として、最も単純な方法はサービスオブジェクトのように素のRubyクラスを定義してそこにユースケースのロジックを実装すること。
    • だけど、ユースケースのロジックを実装するレイヤーの場合にはActive Modelを利用した方が良いとのこと。
    • ActiveModelはモデルに関するモジュール群を提供するライブラリのことでActiveRecordの実装に利用されている。
    • ActiveModelを利用することで、自分で定義した素のRubyクラスにもActiveRecordと同等のインターフェースや機能を追加できる。
    • ActiveModelには色々な種類があって、今日までのところの部分は梅本さんの説明もあって、ふわっとですが理解はできたかな〜という感じです。そして、こういうものがあるんだな、と覚えておきたいと思います。
    • 久しぶりというところもあって、頭がまだ追いついていないところもあっ他ので、後で今日のところをもう一度目を通してみたいと思います。
  • @moegi29

    • ActiveModelを使うことで自分で作った素のRubyクラスを定義してActiveRecordと同等の機能を追加できたり、DBと紐づかないモデルを作れる。会員登録の例でイメージつきました
    • ActiveModelはモデルに関するモジュール群を提供するライブラリ。
      • ActiveModel::Attributes 型を持つ属性の定義や変換?を簡単にしてくれる
      • ActiveModel::Callbacks 動き的にはJSのコールバックと一緒のものと考えてよさそう
      • ActiveModel::Serialization オブジェクトのシリアライズ(直列化)機能の実装を簡単にしてくれるもの
  • motohiro-mm

    • データベースと紐づかないモデルは、ActiveRecordの機能をもたないので、ActiveModelを使うことでActiveRecordと同等の機能を追加できる
    • ActiveModel::Attributes :型を持つ属性の定義を容易にしてくれるモジュール
    • ActiveModel::Callbacks :コールバック機能の実装を容易にするモジュール
      • define_model_callbacks 対象メソッド
      • コールバックの対象となるメソッドの中身をrun_callbacksメソッドのブロックで囲う必要がある
      • なんでこれだけextendなのか気になりました
        • define_model_callbacks はクラスメソッドだからです。include して生えるのはインスタンスメソッド
    • ActiveModel::Serialization :オブジェクトのシリアライズ機能の実装を容易にしてくれるモジュール
  • sakanobu

    • 「PORO なクラスを作ってデータベースとは直接結びつかないモデルも作成可能」ということが強調されていたが、cafedomancer さんの例のようにその PORO なクラスのメソッド内ではデータベースと結びつくモデルを new したり save したりするっぽい(?)ので、PORO なクラスの内部からデータベースと結びつくもの全てを消し去るということが目的ではないんだなと理解が難しかった
      • たしかに完全にデータベースを一切利用しないクラスだと結局どこかでデータを保存しなくちゃ意味がないので、たしかにそうか…みたいな印象です
    • ActiveModel::◯◯ 系のモジュール(?)は自作の PORO なクラスを ActiveRecord を継承したモデルっぽく魔改造するモジュール群なんだなと理解しました
      • ActiveModel のモジュールをいくつか読み込めばたとえ自作の PORO なモデルだったとしても View の form_with メソッドの model: の部分に渡して上手く動くみたいな
  • @shodan

    • データベースに紐づかないモデル(のようなクラス)を作るには、いくつかの手法がある。
    • 素のRubyクラス(PORO)をそのまま書いて使うのもいいけれど、Railsのレールに乗せづらいことが欠点(form_withとか)。
    • ActiveRecordのインターフェースと同等のものを自分で作ったDBに紐づかないクラスで使えるようにするときに、ActiveModelというライブラリが便利。
      • ActiveModel::Attributesは型を持つ属性を簡単に定義できる。
      • ActiveModel::Callbacksはコールバック機能を簡単に定義できる。
      • ActiveModel::Serializationはモデルのインスタンスのシリアライズ機能(別の形式、XMLやJSONへの変換)を簡単に定義できる。
    • こういう言い方が正しいのかはよくわからないですが、こうしたレールをちょっと外れることもサッと自分で定義できるようになれるとかっこいいな〜と思います。
  • @sadanora

    • 素のRubyのクラス
      • PORO(Plain Old Ruby Object)
      • 本の文脈だとActiveRecord::Baseのような基底クラスを継承していないオブジェクト
      • POROはActiveRecordと関係がないので、DBと紐づいているモデルで使えるようなメソッドが使えないけど、ActiveModelによってActiveRecordと同じ機能を色々使えるようにできる。
    • 梅本さんの会員登録の例がわかりやすかったです。
    • シリアライズ
      • 直列化
      • Ruby上のオブジェクトを何らかのファイルに出力しておいて、あとでまた読み込み直せるようにすること

    • 最近左手の手首が痛い
  • @sugiwe

    • ActiveModelを使うと、Railsの恩恵を受けながら複雑なユースケースを実現できる。Railsの恩恵とは、例えばActiveModel::Attributesで自動の型変換をしてくれる、など
    • 梅本さんの会員登録の例(RailsのモデルはUser、Address、Phoneだけど会員登録用に素のRubyでMemberクラスを作る的な)で、「DBに紐づかないモデル」ってのがめっちゃ腑に落ちました。
    • RailsのコールバックとJSのコールバックは、非なるもので混乱するなぁと思っていたが、同じことらしい…!JSのコールバックもちゃんと理解できてないので、セットで理解を深めたいと思いました。
    • 現在、背中を痛めています笑
  • @cafedomancer

    • 雰囲気が暗いですよ!がんばれ!笑
    • なんか会員登録の例は、後ろの方にあるフォームオブジェクトのところで同じような説明があるかも (ちゃんと読んでない) 。ネタバレしてしまったかも。フォームオブジェクトの説明がたぶんより分かりやすくなるのではないかな〜と思います。

2024-03-12(火)

ファシリ

@sugiwe

ドライバー

読んだところ

481p 「🔳 ActiveModel::Validations」から
12-3-3 「実装例」まで。
PR:

次回

12-3-4 「共通のバリデーションルールを定義する」から。🚂

学んだこと・感想

  • @sharoa

    • ActiveModel::Validations⇨属性のバリデーション機能の実装を容易してくれるモジュールのこと。includeするだけで、 ActiveRecordのようにバリデーションを設定して実行できるようになる。
    • 注意点として、includeしただけではbefore_validation,after_validationコールバックは利用できない。
    • ⇧を使いたかったら、さらにActiveModel::Validations::Callbacksをincludeする。(ながいw)
    • ActiveModel::Model⇨ActiveModelが提供するモジュール群の一部をまとめたモジュール。複数のモジュールを組み合わせてコントローラやビューのメソッドとの連携に必要なインターフェースを提供してくれるとのこと。一番便利な子??になるのかな??
    • フォームオブジェクトのところは、ここ数日の中では一番理解しやすかった。(少し嬉しかったですw)
    • でもまだ難しいので、こういうものがあるんだな、と覚えておきたいと思う。
    • 兎にも角にも、今回の例でいうとUserモデルが肥大化することは避けようってことね。
  • @sugiwe

    • .downcase.titleize.capitalizeは動作としては同じ?? .titleizeはRails(ActiveSupport)のメソッドらしい
    • フォームオブジェクトの意義のようなものはフワッとわかったような気がする
      • ユースケースが複数ある場合にそのユースケース固有のロジックは切り分けておいて、Railsのモデルには共通ロジックだけ書くようにするとスッキリする、という感じ(仮にユースケースが1つでも、将来増えることを見越して切り分けられると良いのかも)
    • 「CSVでまとめてアップできないの?」みたいな話はとてもよく聞くので、Webアプリとかでそういう機能がないと残念な気持ちになっていたけど、ちゃんと実装するのは大変なんだなぁと思った
    • 実装の細かい部分は追いつけてない気がするので、要復習…
  • @sakanobu

    • 仕様変更や追加によって特殊なユースケースがドンドン増えていき、User モデル内で validate :fugapiyo_validate, if: hoge?if: hoge? のような条件分岐もドンドン増えていくと、「え、自分のユースケースに関係ないバリデーションが発火しちゃってバリデーションが通らない…」みたいなことが起きるのはたしかに想像できるので、特殊なユースケースのロジックは分離しようね!という話だと理解しました
    • 2024.03.04 の自分のまとめで「ユースケースは実装でいうとバリデーションとコールバックに対応する」的なことを書いてしまったのですが、ユースケースのロジックを分離した後のリスト12.17 app/models/user.rb の実装を見るにバリデーションはまだモデル内に残っているので、バリデーションはユースケースに固有のものと考えずに、ユースケースやモデルなどどこでも書きうるものなんだと認識を改めました
    • Web ページのフォームには関係ないけど特定のユースケースでしか使わないロジックをまとめる PORO を新しく作る場合、app/forms 内には入れず app/models 内に入れていいのか?というファイルの置き場所が気になりました
  • @shodan

    • フォームオブジェクトについて。
      • form_withで属性を設定するモデルのオブジェクトとして、@userとかではなく@user_registration_formのようなフォームを抽象化したモデルを渡すようにする作戦。
      • user_registration_form.saveのようなメソッドを自分で定義しておき、そのsaveの中でUser.new.saveのような登録処理や、そのあとのメール送信処理などを用意しておく。
      • こうすることで、Userモデルから登録というユースケースにまつわるロジックを分離できる。
    • appというオブジェクトからルーティングヘルパーにアクセスできることを初めて知りました!知見。https://railsguides.jp/command_line.html#appオブジェクトとhelperオブジェクト
    • 相変わらず激ムズ。
  • @motohiro-mm

    • ActiveModel::Validations : バリデーション機能の実装を容易にする
      • before_validation,after_validationはActiveModel::Validations::Callbacks
    • ActiveModel::Model : ActiveModelのモジュール群の一部をまとめたモジュール
    • フォームオブジェクト
      • form_withとの連携するユースケースのときに、それらのロジックを実装するオブジェクト。
      • 複数のユースケースがあってメインのモデルが肥大化しちゃうときにフォームオブジェクトをわけることでモデルの肥大化をへらせる
    • 自分は書籍を読んだ時に読み違いや勘違いがとても多いのでずれた質問をしてしまったりすることも多い中、みなさんがいつも真摯に答えてくださることにとても感謝してます。ありがとうございます。
    • 喉に痰がからんでおっさんみたいな咳がでるのをなんとかしたい
  • @sadanora

    • フォームオブジェクト
      • ユースケースを実装するオブジェクト(アプリケーションサービスやインタラクター)は、あるユースケースの一部や全体の処理に対応するメソッドをもつ。
      • これらにform_withとの連携に必要なインターフェースを持たせたものをフォームオブジェクトという。
      • フォームオブジェクトによって、複数のユースケースのロジックによってモデルが肥大化することを防げる。
        • ex) ユーザー登録が、フォームからの登録や管理者によるCSV登録など複数のユースケースが存在する場合に、ユーザー登録のロジックをフォームオブジェクトに分離する。
        • どちらのユースケースでもフォームオブジェクトを呼ぶだけでよくなる
        • みたいなかんじ
        • フォームを抽象化して使いまわせるようにしたって感じなのかな?
        • そういうわけでもなさそう。復習します。
  • @moegi

    • ActiveModelのモジュール群紹介のつづき
      • ActiveModel::Validations includeするだけでactiveRecordのようにバリデーションを設定して実行できる
      • ActiveModel::Model モジュール群の一部をまとめたモジュール。コントローラやビューのメソッドとの連携に必要なインターフェースを提供する。
    • フォームオブジェクトはあるユースケースの一部または全体の処理に対応するメソッドにform_withとの連携に必要なインタフェースを持たせたもの。フォームオブジェクトを使うとUserモデルの肥大化を防げる。実装例の部分、読み解けなかったので復習します。

2024-03-13(水)

ファシリ

@sugiwe

ドライバー

読んだところ

12-3-4 「共通のバリデーションルールを定義する」から
12-4-2 「プレゼンター」まで。
PR:

次回

12-4-3 「ActiveDecorator」から。🚂

学んだこと・感想

  • @sharoa

    • フォームオブジェクトとモデルの間で共通のバリデーションルールが複数存在する場合、このルールを定義して利用するための基底クラスとしてActiveModel::EachValidatorActiveModel::Validatorが用意されている。
    • ActiveModel::EachValidator⇨あるひとつの属性のバリデーションルールを定義する時に利用するもの。(本での例だと、emailのフォーマットに関するルール。)
    • ActiveModel::Validator⇨複数の属性を組み合わせたバリデーションルールなど、より複雑なルールを定義するときに利用するもの。
    • プレゼンターとはコントローラ単位ではなくビューに渡すオブジェクトの単位で表示に関するロジックを整理することでビューヘルパーの問題点を解決してくれるもの。(問題点とは、、、あるモジュールに実装したヘルパ〜は全てのコントローラビューで利用できてしまうことなど。)
    • 明日以降でプレゼンターのgemを紹介してくれているので、また明日を楽しみにしておきます。
  • @sugiwe

    • ActiveModel::EachValidatorは1つの属性のバリデーションルールを定義する時に使う
      • Emailが正しいかどうかをチェックする時など
    • ActiveModel::Validatorは複数の属性を組み合わせたバリデーションルールを定義する時に使う
      • 開始時間と終了時間の両方を使ったチェック(例:開始時間より終了時間のが早いのはNG)する時など
    • ビューヘルパーは、本来使いたいモデルのViewとは関係のないViewからでも呼び出せてしまう。多少はそれで良いかもだけど数が増えてくると名前の重複など管理が難しくなってくる。
    • それを防ぐには、設定によって特定のビューヘルパーを使えるViewを指定できるけど、今度は「複数のコントローラの間で使いたい」って場合に困ることになる。それを解決するのがプレゼンターってコト?😵‍💫
  • @sakanobu

    • ActiveModel::EachValidator を使って HogeFugaValidator という自作の独自のバリデーションを呼び出す際に、validates :email, hoge_fuga: true とすれば HogeFugaValidator の new などをしなくても勝手にバリデーションのインスタンスの生成やその実行をしてくれるというのはまさに Rails の設定より規約という思想だなぁと感じました
    • これまでの章で、「Controller に書くとマズいから Model に移す」「しかし、Model に移したとしても特定の属性にだけ関わるロジックや特定のユースケースのロジックや複数の Model 間で重複するバリデーションなどの再利用できそうなロジックなどが Model にドンドン増えてくるとキツいので、それらを PORO などに移す」と MVC の C と M の整理方法を学んできましたが、とうとう View の部分の整理方法を学ぶところまで来たということであと少しで終わるのかな…という気持ちになってきました
  • @sadanora

    • ActiveModel::EachValidator
      • 1つの属性のバリデーションルールを定義できる
    • ActiveModel::Validator
      • 複数の属性を組み合わせたバリデーションルールなど、ActiveModel::EachValidatorより複雑なルールを定義できる
    • ビューヘルパーを普通にapp/helpers配下に追加すると、すべてのコントローラーのビューで使えてしまう。
      • プレゼンターを導入するとビューヘルパーの呼び出しの多くをビューに渡したオブジェクトのメソッドの呼び出しに置き換えることができる
    • 内容もコードも難しい。本に書いてある事実と自分の推測が曖昧になるので注意したい😵‍💫
  • @moegi29

    • Railsではルールを定義して利用するための基底クラスとしてActiveModel::EachValidatorとActiveModel::Validatorが用意されている
      • ActiveModel::EachValidator 1つの属性のバリデーションルールを定義するときに使う
      • ActiveModel::Validator 複数の属性を組み合わせたときなど複雑なルールを定義するときに使う
    • ヘルパーの数が多くなると名前の重複を避けることが難しくなることがビューヘルパーの問題点っぽい→プレゼンターを導入する(コントローラ単位でなくビューに渡すオブジェクトの単位で表示に関するロジックを整理できる)
  • @motohiro-mm

    • 共通のバリデーションルールを定義したい場合は2種類
      • ある1つの属性(例:email)→ActiveModel::EachValidator
      • 複数の属性(例:期間(開始と終了))→ActiveModel::Validator
    • プレゼンター:コントローラ単位ではなくビューに渡すオブジェクト単位でビューに関するロジックを整理できるもの。以下の問題点を解消している。
      • ビューで使うロジックをモデルの中に置くのは責務違いなので良くない
      • ビューで使うロジックをビューヘルパーにそのまま定義するとどこのコントローラーからでも使えるし名前の重複も起こるかもしれないので良くない
    • 連続で毎日学習できる喜びをかみしめています…

2024-03-14(木)

ファシリ

ドライバー

読んだところ

12-4-3 「ActiveDecorator」から

PR:

次回

13-1-4 「ActiveSupport::Concern」から。🚂

学んだこと・感想

  • @sharoa

    • 単純なプレゼンターであれば自分で実装できるかもしれないが、実用に耐えうるものを作ろうと思うと手間がかかるし、それを保守するのにも手間がかかるらしい。あとRailsにはプレゼンターの実装に利用できる仕組みが用意されていないとのこと。
    • そこで、プレゼンターを実装したgem(本の紹介だとActive Decorator)を利用することが現実的らしい。
    • Active Decoratorでは、プレゼンターに実装したメソッドは基本的にはビューの中でしか使えない。
    • Consernとは、Railsではあるモデルやコントローラを構成する一部の概念や機能を実装するモジュールのことをさす。
    • 496pのモデルに書いてあったものから、利用例として書かれたものを見ると、こうやって使うんだな、というものが見えてよかったな、と思いましたが、何でもかんでもConcernを使えばいいわけではないので、ここの文章を後でもう一度目を通して頭の片隅に置いておきたいと思いました。
  • @sadanora

    • プレゼンターの実装に利用できる仕組みがRailsには用意されていない。自前で実装するか、ActiveDecoratorなどのgemを使う。
    • Concern
      • 日本語で「関心ごと」
      • あるモデルやコントローラを構成する一部の概念や機能を実装するモジュールのこと
      • 安易にConcernで実装すると逆にコードの見通しが悪くなる
        • 値オブジェクトやサービスオブジェクト、モデルやフォームオブジェクトで実装できるか検討した上でどれも適当でないならConcernを選択する
  • @moegi29

    • プレゼンターを実装したgemでActiveDecoratorというものがある。ActiveDecoratorでプレゼンターを実装したメソッドはビューの中でしか利用できないので注意。
    • レイヤーとしてPresenter、小さめの実装としてDecoratorというものがある。
    • RailsにおいてのConcernはあるモデルやコントローラを構成する一部の概念や機能を実装するモジュールのことを指す。
    • Concernを使うことで特定の概念や機能に関するロジックをモデル、コントローラと分けたり再利用できたりする。
    • Concernを使うと見通しが悪くなる場合があるのでいろいろ考えた上で使ったほうが良さそう。
  • @sakanobu

    • ActiveSupport::Concern を使うとコントローラーやモデルに実装するロジックを何でも切り出せてしまうがこれは最終兵器で乱用注意、今まで勉強したロジックの切り出し方をまず検討してから Concern として切り出すかどうか判断する
      • まずは Skinny Controller, Fat Model を意識して Model に移せるものは移す
      • Model の個々の属性に関わるロジックは値オブジェクト
      • Model のインスタンスメソッドとして実装するのがおかしいドメインロジックはサービスオブジェクト or 新たな Model 創出
      • Model に実装すべきロジックだがある特定のユースケースにしか使われないロジックならフォームオブジェクト
      • Model の表示方法に関するロジックはプレゼンター
      • 上記でもダメならやっと Concern を検討
    • shodan さんや sadanora さんが Decorator や Concern についてフィヨルドのチーム開発という具体例を通して紹介してくれたのでイメージがとてもしやすかったです、感謝です!
  • @motohiro-mm

    • ActiveDecorator:プレゼンターを実装できるgem
      • 定義したメソッドはビューでしか利用できないので注意
      • プレゼンターを定義するモジュール名はデフォルトでは#{対象のモデル名}Decoratorなので#{対象のモデル名}Presenterに書き換える
        • なぜ?:プレゼンターはアーキテクチャパターンの構造としての呼び名で、その中にデコレーターがある感じだから
    • プレゼンターはチーム開発でもよく指摘されるらしい
    • Concern:controllersとmodelsのディレクトリに用意されている。データ操作に関するロジックとモデルの関連付けの宣言を行うレイヤー。
      • Concernの定義は曖昧なので、なんでも入れないように(見通し悪くなる)、ほかのもの(値オブジェクト等)を検討した上で該当しなかった場合にconcernを選択すると良い
  • @shodan

    • ActiveDecoratorは実際に使うとめっちゃ便利だな〜すっきりするな〜って感じがするgemでした。
    • Concernは地味にRailsガイドの最初のチュートリアル(タイトルは「Railsをはじめよう」)の中で説明されてて、はじめてやったときは「???」だったことが印象深いです。
    • いまはさらに「?????」なんですが、パRailsで勉強したいと思います。

2024-03-15(金)

ファシリ

@sugiwe

ドライバー

読んだところ

13-1-4 「ActiveSupport::Concern」から
13-1-5 「ルーティングにおけるConsern」まで。
PR:

次回

13-2 「コールバックオブジェクト」から。🚂

学んだこと・感想

  • @sugiwe

    • 昨日休んでてConcernがハテナでしたが、ここまで出てきたものと同様に重複化したものを共通化したり複数出てくるものを切り出して再利用できるようにする?みたいなことかなと受け止めました
    • ActiveSupport::ConcernはConcernの実装を容易にしてくれるメソッド。次の機能がある
      • includedメソッド
      • class_methodsメソッド
      • モジュール間の依存関係の解決
    • Railsガイドのルーティングの記事が分かりやすそうだったので復習します
    • ついに来週終わりそうでドキドキ
  • @sakanobu

    • p.501~504のモジュール間の依存関係の解決のコードの分かりにくさは、そもそも Foo モジュールを Bar モジュールと Baz クラスの両方から呼んで使うという設計(というか依存関係?)になっている時点で大分苦しいなという気持ちになりました
      • ただそうせざるを得ないような仕方ない時も多々あるんだろうなぁとも思いました…
    • ルーティングの concern についてはそもそも自分のルーティングへの知識が曖昧だったので理解が苦労しました
      • concern を使わずにリスト13.11と同じことを実現するコードを自分で書いてみて比較してみようと思います
  • @shodan

    • モデルとコンロトーラのconcern
      • includeされたときに実行したいことを書く場所 -> included メソッドに渡したブロック
      • includeされたクラスのクラスメソッドにしたいメソッドを書く場所 -> class_methodsメソッドに渡したブロック
      • includeされたクラスのインスタンスメソッドにしたいメソッドを書く場所 -> モジュール直下(普通のRubyのモジュールのメソッド定義)
    • ここを整理できただけでもよかったです。
    • ActiveSupport::Concernをextendして作られたモジュールの継承関係の解決
      • Aモジュール、Aのメソッドを使ったBモジュール、Aに依存したBのメソッドを使ったCクラス、のような入り組んだ継承関係を考える
      • A,BともにActiveSupport::Concernextendして定義しておくと、最終的にCではBを読み込むだけで継承関係を意識せずに(?)使うことができるようになる
    • ルーティングにもconcernがあって、共通のルーティング設定を抽出して使いまわせるようにできるらしい
  • @sadanora

    • ActiveSupport::Concernclass_methodsを使うとクラスメソッドの定義を容易に出来る
      • モジュールの中にネストしたClassMethodsモジュールを定義する、みたいな書き方をしなくていい
    • BarモジュールでFooモジュールをextendすると、Fooモジュールのクラスメソッドが使えるようになる→わかる
    • BarモジュールをextendしたBazモジュールではFooモジュールのクラスメソッドは使えない→わかる
      • 各モジュールでActiveSupport::Concernをextendすると、これができるようになる →まじか
    • 継承関係ややこしくて頭こんがらがる
  • @ motohiro-mm

    • ActiveSuppert::Concernをextendすると、モジュールをincludeしただけで、モジュールに定義されたメソッドをクラスメソッドとしてもインスタンスメソッドとしても使えるようになる
      • クラスメソッドの定義の仕方module ClassMethods def メソッド名 ~ end end
    • ActiceSuppert::Concernをextendすることで継承関係を順を追う感じ(直感的な感じ?)でとらえることができる
    • concernはルーティングにおいても使うことができて、共通部分を抽出して使いまわすことができる
      • ルーティングの知識が浅すぎて復習しないと…

Select a repo