How to validate if a string is json in a Rails model

I suppose you could parse the field in question and see if it throws an error. Here's a simplified example (you might want to drop the double bang for something a bit clearer):

require 'json'

class String
  def is_json?
    begin
      !!JSON.parse(self)
    rescue
      false
    end
  end
end

Then you could use this string extension in a custom validator.

validate :json_format

protected

  def json_format
    errors[:base] << "not in json format" unless json.is_json?
  end

The best way is to add a method to the JSON module !

Put this in your config/application.rb :

module JSON
  def self.is_json?(foo)
    begin
      return false unless foo.is_a?(String)
      JSON.parse(foo).all?
    rescue JSON::ParserError
      false
    end 
  end
end

Now you'll be enable to use it anywhere ('controller, model, view,...'), just like this :

puts 'it is json' if JSON.is_json?(something)

Currently (Rails 3/Rails 4) I would prefer a custom validator. Also see https://gist.github.com/joost/7ee5fbcc40e377369351.

# Put this code in lib/validators/json_validator.rb
# Usage in your model:
#   validates :json_attribute, presence: true, json: true
#
# To have a detailed error use something like:
#   validates :json_attribute, presence: true, json: {message: :some_i18n_key}
# In your yaml use:
#   some_i18n_key: "detailed exception message: %{exception_message}"
class JsonValidator < ActiveModel::EachValidator

  def initialize(options)
    options.reverse_merge!(:message => :invalid)
    super(options)
  end

  def validate_each(record, attribute, value)
    value = value.strip if value.is_a?(String)
    ActiveSupport::JSON.decode(value)
  rescue MultiJson::LoadError, TypeError => exception
    record.errors.add(attribute, options[:message], exception_message: exception.message)
  end

end