読者です 読者をやめる 読者になる 読者になる

auto_strip_attributes を紙でコードリーディングしてみた

Rails でフォームのテキストフィールドを保存するときに

  • 先頭の半角スペース / 全角スペース
  • 末尾の半角スペース / 全角スペース

を自動で除去したいという要求があった.

別に Gem を使うまでもなく実現できそうだけど,調べたところ auto_strip_attributes が良さそうだなーという感じだった.

使ってみた

README に書いてある通り,モデルにフィールドを定義するだけで使えた.簡単!

ただし自動で除去されるのは「半角スペース」だけで「全角スペース」は除去されなかった.

auto_strip_attributes :name

Gem をコードリーディングしてみた

auto_strip_attributes.rb を見ると86行しかなくて,シンプルな Gem だったので,Ruby の勉強を兼ねてコードリーディングしてみた.

README を見たらわかることも多いけど,自分でコードを読むことも重要!わかったことを簡単にメモしておこうと思う.

1.

Gem のロード時に ActiveRecord に extend してから setup を呼び出していた.

ActiveRecord::Base.send(:extend, AutoStripAttributes) if defined? ActiveRecord
AutoStripAttributes::Config.setup

2.

この Gem の正体は指定されたフィールドごとに before_validation を定義していた.よって変換をした後の状態でモデルのバリデーションが走ることがわかる.

attributes.each do |attribute|
  before_validation do |record|
    # (中略)
  end
end

3.

README に書いてある通りだけど,計5種類のデフォルトフィルタが定義されている.

nullify ってデフォルトで ON なんだなーと思った.

フィルタ名 デフォルト設定 概要
convert_non_breaking_spaces OFF NonBreakingSpace を半角スペースに変換する
strip ON 先頭と末尾の半角スペースを除去する
nullify ON .blank? = true な場合自動で nil に変換する
squish OFF 文字列空白(タブなどを含む)を半角スペースに変換する
delete_whitespaces OFF 文字列全体の半角スペースとタブを除去する

4.

上記のデフォルトフィルタ以外に独自フィルタを定義できる.

instance_eval &block if block_given?

5.

README に独自フィルタの例が書いてあるけど,デフォルト設定が false なら set_filter にフィルタ名だけを指定することもできる.

:strip_html => false じゃなくて :strip_html とも書ける.

AutoStripAttributes::Config.setup do
  set_filter :strip_html => false do |value|
    ActionController::Base.helpers.strip_tags value
  end
end

ここを見ると filter.is_a?(Hash) で分岐していた.

if filter.is_a?(Hash) then
  filter_name = filter.keys.first
  filter_enabled = filter.values.first
else
  filter_name = filter
  filter_enabled = false
end

紙でコードリーディング

今回は RubyMine に頼らずに,コードをプリントしてメモしながらコードリーディングしてみた.

SIer 時代によくやったなー!と懐かしさを感じたけど,読みながら頭の中を整理できるし,エディタで読むよりも理解が早かったかも!

(時間使ってないでサクッと読めなんて言わないで!ビギナーだから!笑)

f:id:kakku22:20150716201210j:plain

独自フィルタを定義してみた

先頭と末尾の全角スペースを除去するフィルタの需要はあると思うので,本家にプルリクしても良いかなと思ったけど,独自フィルタの機能がせっかくあることだし使ってみた.

config/initializers/auto_strip_attributes.rb を追加して以下の独自フィルタを書いた.

AutoStripAttributes::Config.setup do
  set_filter strip_double_byte_space: false do |value|
    unless value.nil? || !value.is_a?(String)
      value.gsub(/(^(\s| )+)|((\s| )+$)/, '')
    end
  end
end

モデル側で strip_double_byte_space: true を定義するだけで使えるし簡単!

auto_strip_attributes :name, strip_double_byte_space: true

まとめ

  • Rails で先頭と末尾の半角スペースを除去したかったら auto_strip_attributes を使うと便利!
  • 先頭と末尾の全角スペースを除去したかったら拡張すれば良し!
  • コードをプリントして読んだら理解が早かった!(個人の感想)