sharoa
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 【第29週】パRails輪読会🚂 \(2024\-03\-04\~ 2024\-03\-15\) ###### tags: `パRails🚂` - [開催概要](https://hackmd.io/4A_8ahJtQNi5hz713N5Y7w?view) - [パRails輪読会 ノートまとめ](https://hackmd.io/jsgA8Pf_RVioOgSL_VOR4g) - サンプルコード・正誤表:[サポートページ:パーフェクトRuby on Rails【増補改訂版】:|技術評論社](https://gihyo.jp/book/2020/978-4-297-11462-6/support) - **サンプルコードをダウンロードしただけでは、すぐに`rails s`できない可能性が高い**です。 以下のページに環境構築の手順をまとめたので、ドライバーをやってくださるという方は、こちらに沿って環境構築をお願いします🙏 ⏩ [環境構築の手順 2022年版](https://hackmd.io/y7qb2BRMT2Wd4tAtKYObcQ) ⏩ [環境構築の手順 2023年版](https://hackmd.io/3_lnn8_QRD6wEjwFbWcBzQ) 💁‍♀️ [更新の手順 2章編](https://hackmd.io/pZAmF2EjSmyQ38lUtJ_CqA) ## 目次 [TOC] ------ ## 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の使い方というよりはオブジェクト思考的な設計とかそういうことな気がする。 - https://www.amazon.co.jp/%E3%81%A1%E3%82%87%E3%81%86%E3%81%9C%E3%81%A4%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E8%A8%AD%E8%A8%88%E5%85%A5%E9%96%80%E2%80%95%E2%80%95PHP%E3%81%A7%E7%90%86%E8%A7%A3%E3%81%99%E3%82%8B%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%AE%E6%B4%BB%E7%94%A8-%E7%94%B0%E4%B8%AD-%E3%81%B2%E3%81%95%E3%81%A6%E3%82%8B/dp/4297132346 - この本がとても良いらしいんですが、表紙の可愛らしさに反してとっても難しいらしいです。 - 上の知識があったときに、それを簡単に実現してくれる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: ](https://github.com/fjordllc/bootcamp/blob/main/app/models/campaign.rb) - ユーザーとアプリケーションの間のやり取りに関するロジック (ユースケースのロジック?) - バリデーション - ただし、モデル専用のバリデーションもあるのでユースケースにしかバリデーションを書かないという意味ではない - コールバック - 「ユーザー登録完了後にウェルカムメールを送信する」という場合の「メール送信」は、やろうと思えば 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%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A8helper%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88 - 相変わらず激ムズ。 - @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::EachValidator` と`ActiveModel::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をはじめよう」)の中で説明されてて、はじめてやったときは「???」だったことが印象深いです。 - https://railsguides.jp/getting_started.html#concern%E3%82%92%E4%BD%BF%E3%81%86 - まずは`rails s`してみよう、みたいなところから始まるチュートリアルなんですが、最後にがっつりConcernの説明が出てきます。 - いまはさらに「?????」なんですが、パ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::Concern`を`extend`して定義しておくと、最終的にCではBを読み込むだけで継承関係を意識せずに(?)使うことができるようになる - ルーティングにもconcernがあって、共通のルーティング設定を抽出して使いまわせるようにできるらしい - @sadanora - `ActiveSupport::Concern`の`class_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はルーティングにおいても使うことができて、共通部分を抽出して使いまわすことができる - ルーティングの知識が浅すぎて復習しないと… -----

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully