Rails: Form ObjectとVirtusを使って属性をサニタイズする(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

Form Objectパターンについては「肥大化したActiveRecordモデルをリファクタリングする7つの方法(翻訳)」もご覧ください。

Rails: Form ObjectとVirtusを使って属性をサニタイズする(翻訳)

私たちはDrivyのコードベースで、Form ObjectのビルドにVirtus gemを使っています。これによって以下のメリットを得られました。

  • コントローラやビューにビジネスロジックを含めないようにする
  • 永続しない属性を取り扱える
  • 特定のバリデーションを、モデルに直接追加せずに追加できる
  • カスタムのデータバリデーションをフォームに直接表示できる
  • includeすることで機能をActiveModel::Modelから使える

ユーザー入力のサニタイズ、データの整形、スペースの除去といった作業が必要になったときに、Virtusを使って行える便利な方法をご紹介します。

#coerceを使う

文字列として記録されているVAT番号からスペースをすべて除去したいとします。シンプルなユースケースですが、このコンセプトはもっと複雑な状況にも適用できます。

まず、サニタイズ対象となる属性のカスタム属性オブジェクトを定義する必要があります。そのオブジェクトで#coerceメソッドを使うためにVirtus::Attributeの継承も必要です。次に、実行したい整形処理をメソッドに定義します。

class SanitizedVatNumber < Virtus::Attribute
  def coerce(value)
    value.respond_to?(:to_s) ? value.to_s.gsub(/\s+/, '') : value
  end
end

次はVirtusのForm Objectでvat_number属性(これが更新対象です)をSanitizedVatNumberとして指定します。

class CompanyForm
  attribute :vat_number, SanitizedVatNumber

  def initialize(...)

  end
end

以上でおしまいです。フォームが送信されるとvat_numberがサニタイズされます。

RSpecでテストする

カスタムのVirtus属性に基本的なテストを追加するのも簡単です。RSpecを使う場合は次のようにします。

describe SanitizedVatNumber do
  let(:object) { described_class.build(described_class) }
  subject { object.coerce(value) }


  context 'vat_numberがnilの場合' do
    let(:value)  { nil }

    it { is_expected.to eq('') }
  end

  context 'vat_numberがスペースを含む場合' do
    let(:value)  { 'EN XX 999 999 999' }

    it { is_expected.to eq('ENXX999999999')}
  end
end

まとめ

Form Objectの責務の増加(属性をフォーム内で直接サニタイズするリスクにつながる)を避けることができます。また、Virtusのカスタム#coerceは複数のフォームで再利用でき、単体テストも非常に行いやすくなります。

本記事が気に入った方はぜひDrivyエンジニアリングチームの募集要項をご覧ください。

関連記事

肥大化したActiveRecordモデルをリファクタリングする7つの方法(翻訳)

Railsで重要なパターンpart 1: Service Object(翻訳)

Railsで重要なパターンpart 2: Query Object(翻訳)

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833 コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。 これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 実は最近Go言語が好き。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ