Two Valuable Custom Validators in Rails

There are a lot of services which request tasks to other system such as analyzing customer actions, batch delivery in e-commerce service, and so on. The simplest way to execute it is handing in a file which is made from the records of DB in our service to other system but we sometimes encounter problems not be able to connect correctly, especially Encode or Linefeed because of a difference of the specification. Therefore, we also need to validate customer’s inputs in accordance with the same specification in our service.

In this article, I’ll share the way to bridge the gap between our service and such a system by making Custom Validator in Rails. Thank you in advance for your understanding that I won’t get in touch with extracting data from DB and requesting to other system.

Custom Encode Validator

As you know, we have to define each Custom Validator under app/validators and I recommend you to create in each encode-validation.

class Cp932Validator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
value.encode('cp932') if value.present?
rescue Encoding::UndefinedConversionError
record.errors[attribute] << (options[:message] || "can't include CP932 characters")
end
end

class ShiftJisValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
value.encode('Shift_JIS') if value.present?
rescue Encoding::UndefinedConversionError
record.errors[attribute] << (options[:message] || "can't include Shift_JIS characters")
end
end

The reason why creating so, we can write like below in each model which makes easier to understand how it would be validated.

validates :name, cp932: true, shift_jis: true

Custom Linefeed Validator

We have to define Custom Validator under app/validators alike.

class SingleLineValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
record.errors[attribute] << (options[:message] || "can't include line feed / carriage return") if value =~ /\R/
end
end

It’s better to name it SingleLineValidator, because we can define like single_line: true which is clear not to accept a new line.

validates :name, single_line: true

Conclusion

We often come across these problems because there are many self-defined systems in Japan. I don’t know clearly there also would be in other countries but I hope that it would be helpful if you face with the same problems.