IpValidatorを追加した
これはRailsアプリケーションの話です。
今回カラムにipを追加し、バリデーションを追加して欲しいとのことでした。
バリデーションはIPv4とIPv6に対応して欲しいということでした。
この記事は、
という話ができたらと思います。
Resolv::IPv4::Regex とResolv::IPv6::Regex というものが用意されていた
正規表現って自分で書くとバグを生んだり、面倒だったりするのでまずはネットで調べると思うのですが、ありがたいことにRubyはいろんなものが用意されています。
Resolv::IPv4::Regex の存在を見つけました。
コンソールで実行してみると、
irb(main):001:0> Resolv::IPv4::Regex => /\A((?x-mi:0 |1(?:[0-9][0-9]?)? |2(?:[0-4][0-9]?|5[0-5]?|[6-9])? |[3-9][0-9]?))\.((?x-mi:0 |1(?:[0-9][0-9]?)? |2(?:[0-4][0-9]?|5[0-5]?|[6-9])? |[3-9][0-9]?))\.((?x-mi:0 |1(?:[0-9][0-9]?)? |2(?:[0-4][0-9]?|5[0-5]?|[6-9])? |[3-9][0-9]?))\.((?x-mi:0 |1(?:[0-9][0-9]?)? |2(?:[0-4][0-9]?|5[0-5]?|[6-9])? |[3-9][0-9]?))\z/
これはすごいですね!
IPv6も動くんじゃないか?と淡い期待をして実行してみました。
やっぱりいました。
irb(main):002:0> Resolv::IPv6::Regex => / (?:(?x-mi:\A (?:[0-9A-Fa-f]{1,4}:){7} [0-9A-Fa-f]{1,4} \z)) | (?:(?x-mi:\A ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) :: ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) \z)) | (?:(?x-mi:\A ((?:[0-9A-Fa-f]{1,4}:){6,6}) (\d+)\.(\d+)\.(\d+)\.(\d+) \z)) | (?:(?x-mi:\A ((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) :: ((?:[0-9A-Fa-f]{1,4}:)*) (\d+)\.(\d+)\.(\d+)\.(\d+) \z))/x
さすがです。
これをいい感じに使用したバリデーターを作ろうと思って作りました。
# frozen_string_literal: true class IpValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) return true if Resolv::IPv4::Regex.match?(value) || Resolv::IPv6::Regex.match?(value) record.errors.add(attribute, :invalid_ip, options) end end
作ったバリデーターを呼ぶには、
# == Schema Information # # Table name:hoges # # id :bigint(8) not null, primary key # ip :string(255) # created_at :datetime not null # updated_at :datetime not null # class Hoge < ApplicationRecord validates :ip, ip: true end
「validates :ip, ip: true」これだけです。
バリデーターを作るところから真似してもらえると幸いです。