Share
Embed
Input object ではじめる入力値検証/input-value-validation-using-input-object
Masatoshi Moritsuka
November 15, 2023
Transcript
29 slides
-
森塚 真年 U GitHub: @sanfrecce-osakc U Twitter(X): @sanfrecce_osakc U Qiita:
@sanfrecce_osakc U from: 大阪府枚方2 U 趣味: コミュニティ・勉強@ U 好きな Ruby の機能: パターンマッ3 U 最近の興味: orthoses-rail8 U 所属: 株式会社エンペイ 自己紹介 -
概要 1 サービb 1 集金業務支援サービス enpa6 1 口座振替業務支援サービス koufuri) 1
モバイル決済アプリ enpayウォレッe 1 技 1 バックエンド: Ruby / Rails / Go / HasurA 1 フロントエンド: Flutter / React / Vue 株式会社エンペイ https://www.enpay.co.jp/ -
最近の予定 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 -
https://speakerdeck.com/daikimiura/upgrow?slide=23 参考資料 Upgrow: Railsアプリの保守性を高めるためのShopify のアプローチ / Upgro Input
object を使ってリクエストパラメータを検証す y ぼくがかんがえたさいきょうの Input object Input object パターン -
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 -
Controller(action) class < def => : end before_action index_inputs [{
ids }] HogeController ApplicationController :validate_params index # ... -
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 -
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を指定してください _ -
Input object(Concern) module extend :: do include :: include ::
end end included Input ActiveSupport ActiveModel ActiveModel Concern Model Attributes -
カスタムタイプ module class < :: :: & end end end
cast_value(value) value.split( ).map( ) Types IntegerArrayType ActiveModel Type Value def [[:blank:] :to_i /, ]*/ -
しばらく運用してみて 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 # ... # ... # ... -
方針変更(予定) 方針 属性ごとに 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 -
共通インターフェース 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 -
Controller(action) class < def => : end def => :
end before_action input { ids } input { hoges } HogeController ApplicationController :validate_params index create # ... -
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 の処理 -
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 _