Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Input object ではじめる入力値検証/input-value-validation-using-input-object

Input object ではじめる入力値検証/input-value-validation-using-input-object

Masatoshi Moritsuka

November 15, 2023
Tweet

More Decks by Masatoshi Moritsuka

Other Decks in Programming

Transcript

  1. 森塚 真年 U GitHub: @sanfrecce-osakc U Twitter(X): @sanfrecce_osakc U Qiita:

    @sanfrecce_osakc U from: 大阪府枚方2 U 趣味: コミュニティ・勉強@ U 好きな Ruby の機能: パターンマッ3 U 最近の興味: orthoses-rail8 U 所属: 株式会社エンペイ 自己紹介
  2. 概要 1 サービb 1 集金業務支援サービス enpa6 1 口座振替業務支援サービス koufuri) 1

    モバイル決済アプリ enpayウォレッe 1 技 1 バックエンド: Ruby / Rails / Go / HasurA 1 フロントエンド: Flutter / React / Vue 株式会社エンペイ https://www.enpay.co.jp/
  3. 最近の予定 10月 0 1週目: 会社のイベントで東# 0 3週目: 大江戸Ruby会議で東# 0 4週目:

    Kaigi on Railsで東京 11月 0 11/15: このイベントで東# 0 11/20: 会社のイベントで東京 12月/1月 0 12/15 RubyConf Taiwan 202— 0 1/13 福岡Rubyフェスタ202i 0 1/20 BuriKaigi
  4. https://speakerdeck.com/daikimiura/upgrow?slide=23 参考資料 – Upgrow: Railsアプリの保守性を高めるためのShopify のアプローチ / Upgroƒ – Input

    object を使ってリクエストパラメータを検証す y – ぼくがかんがえたさいきょうの Input object Input object パターン
  5. Text enpay での場合 方針 g 属性ごとに Input object 作R g

    API として想定外のもののみバリデーションの対& g クエリを発行するような処理は行わない ディレクトリ構成 g model† g input† g boolean_input.r• g ids_input.r• g keywords_input.r• g type† g integer_array_type.r• g string_array_type.rb
  6. Controller(action) class < def => : end before_action index_inputs [{

    ids }] HogeController ApplicationController :validate_params index # ...
  7. Controller(private methods) private def unless & end def end def

    ||= :: new : end head , index_inputs.all?( ) [ids_input] . (ids params[ ]) validate_params index_inputs ids_input :bad_request :valid? @ids_input :ids Inputs IdsInput
  8. Input object module class include :: new : def **

    super ** end def unless & end def : end end end attribute , . , default { } validate ( args) ( args.compact_blank) errors.add( , ) ids.all?( ) ( ) { ids } Inputs IdsInput Types IntegerArrayType -> Input :ids :should_be_positive_all :base :positive? '' ' ' initialize should_be_positive_all deconstruct_keys 有効なIDを指定してください _
  9. Input object(Concern) module extend :: do include :: include ::

    end end included Input ActiveSupport ActiveModel ActiveModel Concern Model Attributes
  10. カスタムタイプ module class < :: :: & end end end

    cast_value(value) value.split( ).map( ) Types IntegerArrayType ActiveModel Type Value def [[:blank:] :to_i /, ]*/
  11. しばらく運用してみて h 更新系APIでも利用され始めg h 導入当初の対象は 参照系API のみだっg h private で大量に生える

    xxx_input メソッ h 複数のアクションで利用され始めg h アクションごとの分岐が増えてきた その後 action_name private def case in then in then end def end def end def end validate_params xxx_input yyy_input zzz_input ' ' ' ' index create # ... # ... # ...
  12. 方針変更(予定) 方針 ˜ 属性ごとに Input object 作ƒ ˜ => Controller

    の action ごとに Input object 作T ˜ => 共通のインターフェースを提8 ˜ API として想定外のもののみバリデーションの対f ˜ クエリを発行するような処理は行わな ˜ generator の提供(未実装) ディレクトリ構成 ˜ model{ ˜ input{ ˜ controller{ ˜ xxx_controllev ˜ index_input.r„ ˜ create_input.r„ ˜ xxx_input.r„ ˜ type{ ˜ xxx_type.rb
  13. 共通インターフェース module def #{ } end def #{ } #{

    } end end send( .to_sym) .constantize Inputs input input_class " " " " action_name _input ::Inputs::Controllers:: .class :: action_name.classify Input self
  14. Controller(action) class < def => : end def => :

    end before_action input { ids } input { hoges } HogeController ApplicationController :validate_params index create # ...
  15. Controller(private methods) private def unless end def ||= new end

    def end head , input.valid? input_class. (create_params) validate_params create_input create_params :bad_request @create_input # ... # Strong Parameter の処理
  16. Input object module module module class include :: :: new

    :: :: new :: :: : : : in : def ** super ** end def : : : end end end end end attribute , attribute , . attribute , . ( , array ), default { [] } validates , inclusion { : } validates , presence ( args) ( args.compact_blank) ( ) { name , status , hoges } Inputs Controllers HogeController CreateInput Types SymbolType Types InputType Inputs -> Input :name :string :status :fugas FugaInput true :status :fugas true %[ ] todo doing done initialize deconstruct_keys _