Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/52.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/json/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何在Rails模型中验证字符串是否为json_Ruby On Rails_Json_Validation - Fatal编程技术网

Ruby on rails 如何在Rails模型中验证字符串是否为json

Ruby on rails 如何在Rails模型中验证字符串是否为json,ruby-on-rails,json,validation,Ruby On Rails,Json,Validation,我正在构建一个简单的应用程序,希望能够在数据库中存储json字符串。我有一个带有json列的表接口,我希望我的rails模型验证字符串的值。比如: class Interface < ActiveRecord::Base attr_accessible :name, :json validates :name, :presence => true, :length => { :minimum => 3,

我正在构建一个简单的应用程序,希望能够在数据库中存储json字符串。我有一个带有json列的表接口,我希望我的rails模型验证字符串的值。比如:

class Interface < ActiveRecord::Base
  attr_accessible :name, :json

  validates :name,  :presence => true,
                    :length   => { :minimum => 3,
                                   :maximum => 40 },
                    :uniqueness => true

  validates :json, :presence => true,
                   :type => json #SOMETHING LIKE THIS
                   :contains => json #OR THIS    
end
类接口true,
:长度=>{:最小=>3,
:最大值=>40},
:唯一性=>true
验证:json,:presence=>true,
:type=>json#类似这样的东西
:contains=>json#或此
结束

我该怎么做呢?

我想您可以解析有问题的字段,看看它是否抛出错误。下面是一个简化的示例(为了更清楚一点,您可能想放弃双重爆炸):

然后可以在自定义验证器中使用此字符串扩展名

validate :json_format

protected

  def json_format
    errors[:base] << "not in json format" unless json.is_json?
  end
validate:json\u格式
受保护的
def json_格式

errors[:base]最好的方法是向JSON模块添加一个方法

将其放入您的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
现在,您可以在任何地方使用它(“控制器、模型、视图等”),如下所示:

puts 'it is json' if JSON.is_json?(something)
目前(Rails 3/Rails 4),我更喜欢自定义验证器。另见

#将此代码放在lib/validators/json_validator.rb中
#在您的模型中的用法:
#验证:json_属性,状态:true,json:true
#
#要获得详细的错误信息,请使用以下方法:
#验证:json_属性,presence:true,json:{message::some_i18n_key}
#在您的yaml使用中:
#some_i18n_键:“详细异常消息:%{exception_message}”
类JsonValidator:无效)
超级(选项)
结束
def验证每个(记录、属性、值)
value=value.strip如果value.is_是?(字符串)
ActiveSupport::JSON.decode(值)
rescue MultiJson::LoadError,TypeError=>异常
record.errors.add(属性,选项[:message],异常消息:exception.message)
结束
结束

使用JSON解析器,可以进行纯JSON格式验证
ActiveSupport::JSON.decode(value)
将值
“123”
123
验证为true。这是不对的

# 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)
    if value.is_a?(Hash) || value.is_a?(Array)
      value = value.to_json
    elsif value.is_a?(String)
      value = value.strip
    end
    JSON.parse(value)
  rescue JSON::ParserError, TypeError => exception
    record.errors.add(attribute, options[:message], exception_message: exception.message)
  end

end
#在您的模型中的用法:
#验证:json_属性,状态:true,json:true
#
#要获得详细的错误信息,请使用以下方法:
#验证:json_属性,presence:true,json:{message::some_i18n_key}
#在您的yaml使用中:
#some_i18n_键:“详细异常消息:%{exception_message}”
类JsonValidator异常
record.errors.add(属性,选项[:message],异常消息:exception.message)
结束
结束

我在使用Rails 4.2.4和PostgreSQL适配器(pg)以及json字段的自定义验证器时遇到了另一个问题

在以下示例中:

class SomeController < BaseController
  def update
    @record.json_field = params[:json_field]
  end
end
它被悄悄地忽略,“nil”存储在

@record.json_field
如果您使用自定义验证器,如

class JsonValidator < ActiveModel::Validator
  def validate(record)
    begin
      JSON.parse(record.json_field)
    rescue
      errors.add(:json_field, 'invalid json')
    end
  end
end
只有“nil”值,因为rails在将值传递给验证器之前进行类型转换。为了克服这个问题,只需使用

record.json_field_before_type_cast

在您的验证器中。

如果您不喜欢企业风格的验证器或猴子修补字符串类,这里有一个简单的解决方案:

validate :json_format

protected

  def json_format
    errors[:base] << "not in json format" unless json.is_json?
  end
class Model < ApplicationRecord
  validate :json_field_format

  def parsed_json_field
    JSON.parse(json_field)
  end

  private

  def json_field_format
    return if json_field.blank?
    begin
      parsed_json_field
    rescue JSON::ParserError => e
      errors[:json_field] << "is not valid JSON" 
    end
  end
end
类模型e

errors[:json_field]最简单、最优雅的方式,依我看。当传递包含整数或浮点数的字符串时,排名靠前的答案将返回true,或者在这种情况下抛出错误

def valid_json?(string)
    hash = Oj.load(string)
    hash.is_a?(Hash) || hash.is_a?(Array)
rescue Oj::ParseError
    false
end

一切都变绿了,谢谢!响应时间也很好:)我一直在尝试做类似的事情,但我的Rails技能有点落后。嗯,这很奇怪。我有rspec测试,其中一个测试需要一个有效的json字符串作为json的值,这些测试都是绿色的。但是我的cucumber测试失败了,在rails服务器中测试视图也失败了,说明是_json吗?是一个未定义的方法。我把你建议的验证类放在了我的模型下面,是不是错了?我想有不同的观点,但似乎大多数人都把他们的核心类扩展放在
config/initializers/
中,作为
*.rb
(自然)在Rails加载后自动加载。另一个选项是
lib/
目录,但是你必须告诉Rails仍然要加载你的文件。这个解决方案非常有效,我做了一次投票,但请允许我简短地说一句:用自己的方法扩展基本对象通常被认为不是最佳实践。我更愿意实现is_json?方法,并提供“可疑的_json”字符串作为该方法的参数。虽然能够在这里使用self真的很优雅:)@awenkhh 2014-me必须同意你,而不是2011-me。也许需要改进;)?事实上,我更喜欢这个想法,而不是公认的答案。使用MultiJson.load(value)而不是ActiveSupport::JSON.decode(value)怎么样?然后,它也会运行到rescue块中……您是否希望替换json_字段,如:
validate:options_format
parsed_options
class Model < ApplicationRecord
  validate :json_field_format

  def parsed_json_field
    JSON.parse(json_field)
  end

  private

  def json_field_format
    return if json_field.blank?
    begin
      parsed_json_field
    rescue JSON::ParserError => e
      errors[:json_field] << "is not valid JSON" 
    end
  end
end
def valid_json?(string)
    hash = Oj.load(string)
    hash.is_a?(Hash) || hash.is_a?(Array)
rescue Oj::ParseError
    false
end