2011-07-06 20 views
25

में एक स्ट्रिंग जेसन है या नहीं, मैं एक सरल ऐप बना रहा हूं और एक डीबी में जेसन स्ट्रिंग को स्टोर करने में सक्षम होना चाहता हूं। मेरे पास एक कॉलम जेसन के साथ एक टेबल इंटरफ़ेस है, और मैं चाहता हूं कि मेरे रेल मॉडल स्ट्रिंग के मान को मान्य करें। तो कुछ ऐसा:रेलवे मॉडल

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 

मैं यह कैसे कर सकता हूं?

उत्तर

33

मुझे लगता है कि आप इस क्षेत्र को प्रश्न में पार्स कर सकते हैं और देख सकते हैं कि यह कोई त्रुटि फेंकता है या नहीं। यहाँ एक सरल उदाहरण है (आप कुछ स्पष्ट के लिए डबल धमाका ड्रॉप करना चाह सकते हैं):

require 'json' 

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

तो फिर तुम एक कस्टम validator में इस स्ट्रिंग एक्सटेंशन का उपयोग कर सकते हैं।

validate :json_format 

protected 

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

और सभी हरे रंग गए, धन्यवाद! महान प्रतिक्रिया समय भी :) मैं ऐसा कुछ करने की कोशिश कर रहा था लेकिन मेरे रेल कौशल थोड़ा धूलदार हैं। –

+0

हम्म, यह अजीब है। मेरे पास rspec परीक्षण हैं, जिनमें से एक को जेसन के लिए मान के रूप में एक वैध जेसन स्ट्रिंग की आवश्यकता होती है, और ये सभी हरे रंग के होते हैं। लेकिन मेरे ककड़ी परीक्षण विफल हो जाते हैं, और रेल सर्वर में दृश्य का परीक्षण भी विफल रहता है, is_json बता रहा है? एक अपरिभाषित विधि है। मैंने आपके मॉडल के नीचे सुझाए गए सत्यापन वर्ग को रखा है, क्या यह गलत है? –

+4

मुझे लगता है कि अलग-अलग राय हैं लेकिन ऐसा लगता है कि ज्यादातर लोग अपने कोर क्लास एक्सटेंशन को 'config/startizers /' में '* .rb' (स्वाभाविक रूप से) में रख रहे हैं जहां रेल लोड होने के बाद वे स्वचालित रूप से लोड हो जाते हैं। एक और विकल्प 'lib/'निर्देशिका है, लेकिन फिर आपको अपनी फाइल लोड करने के लिए रेल को अभी भी बताना होगा। – polarblau

14

जेएसओएन मॉड्यूल में एक विधि जोड़ने का सबसे अच्छा तरीका है!

अपने 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) 
14

वर्तमान में (रेल 3/रेल 4) मैं एक कस्टम सत्यापनकर्ता पसंद करेंगे। 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 
+0

@polarblau। ActiveSupport :: JSON.decode (value) के बजाय MultiJson.load (value) का उपयोग करने के बारे में कैसे? इसके बाद यह बचाव ब्लॉक में भी चला जाएगा ... – mfittko

0

JSON पार्सर का उपयोग करके, शुद्ध JSON प्रारूप सत्यापन संभव है। ActiveSupport::JSON.decode(value) मूल्य "123" और 123 मान्य करने के लिए मान्य करता है। वह सही नहीं है!

# 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 
3

मैं अपने json क्षेत्र के लिए रेल 4.2.4 और PostgreSQL अनुकूलक (पीजी) और कस्टम सत्यापनकर्ता का उपयोग कर एक और समस्या का सामना करना पड़ा।

निम्न उदाहरण में: आप का उपयोग करते हैं

class SomeController < BaseController 
    def update 
    @record.json_field = params[:json_field] 
    end 
end 

अगर आप

params[:json_field] 

यह चुपचाप नजरअंदाज कर दिया है और "शून्य" के लिए अमान्य JSON पारित

@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 

आप नहीं,

record.json_field 
केवल

"शून्य" मूल्य में अवैध स्ट्रिंग देखते हैं क्योंकि रेल सत्यापनकर्ता करने के लिए अपने मूल्य के पार करने से पहले कास्टिंग टाइप करता होगा। इस पर काबू पाने के लिए, बस अपने सत्यापनकर्ता में

record.json_field_before_type_cast 

का उपयोग करें।

संबंधित मुद्दे