2017-07-11 6 views
3

Railsを使用してオブジェクトの配列内の各オブジェクトをどのように検証しますか?RubyOnRailsを使用したjsonbオブジェクトの配列内のオブジェクトの検証

私はRailsアプリケーションでユーザープロフィールフォームを作成しています。ユーザーモデルの中には、基本的な文字列属性がありますが、いくつかのjsonbフィールドもあります。 JSONbフィールドのデフォルト値は[]です。その属性内にオブジェクトの配列を格納したいからです。ここでユーザの簡易モデルの一例は、属性れる:

[{ 
    school: 'Harvard university', 
    degree: 'Computer Science', 
    from_date: 'Tue, 11 Jul 2017 16:22:12 +0200`, 
    to_date: 'Tue, 11 Jul 2017 16:22:12 +0200' 
},{ 
    school: 'High school', 
    degree: 'Whatever', 
    from_date: 'Tue, 11 Jul 2017 16:22:12 +0200`, 
    to_date: 'Tue, 11 Jul 2017 16:22:12 +0200' 
}] 

ユーザーでなければならない:

  • name: string
  • email: string
  • education: jsonb, default: []

教育のようなオブジェクトの配列でありますクリックすることができますschoを追加olボタン、jqueryでさらにフィールドを追加します。そのjqueryの部分はこの質問にとって重要ではありません - 私たちがオブジェクトの配列を使用した理由を説明するだけかもしれません。

教育用配列の各項目をどのように検証すると、有効なエラーを含むテキストフィールドに赤色のマークを付けることができますか?私は、FormObjectパターンを使用するとここで助けになるとアドバイスを受けました。私もActiveModel::Validatorクラスから継承したカスタムバリデーターを作成しようとしましたが、主な問題は実際には配列であり実際のオブジェクトではないことにあります。

ありがとうございました。

答えて

3

あなたは、あなたの中で第一級の市民としての教育記録を扱うことができ

class Education 
    include ActiveModel::Model 

    attr_accessor :school, :degree, :from_date, :to_date 

    validates :school, presence: true 
    validates :degree, presence: true 

    def initialize(**attrs) 
    attrs.each do |attr, value| 
     send("#{attr}=", value) 
    end 
    end 

    def attributes 
    [:school, :degree, :from_date, :to_date].inject({}) do |hash, attr| 
     hash[attr] = send(attr) 
     hash 
    end 
    end 

    class ArraySerializer 
    class << self 
     def load(arr) 
     arr.map do |item| 
      Education.new(item) 
     end 
     end 

     def dump(arr) 
     arr.map(&:attributes) 
     end 
    end 
    end 
end 

次にあなたが透過的にあなたのUserモデルでeducation配列シリアライズとデシリアライズすることができます:

class User 
    # ... 
    serialize :education, Education::ArraySerializer 
    # ... 
end 
012を彼らのために ActiveModelモデルクラスを担保非データベースを導入することにより、Railsのモデル層

このソリューションでは、組み込みのRailsバリデーターを持つオブジェクトEducationの個々の属性を検証し、ネストされたフォームに埋め込むことができます。

重要:私は上記のコードをテストせずに書きましたので、いくつか変更する必要があります。

0

これはおそらく何か? (おそらく、ハッシュは文字列としてのキーではなく記号で渡された後、アイテムのために検証されることになるでしょう[文字列]でないアイテム[シンボル]

class MyModel < ActiveRecord::Base 
    include ActiveModel::Validations 
    validates :education, evalidation: true 

    class EvalidationValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value) 
     record.errors[attribute] << "must be a valid array & json" unless (check_json_array(value) rescue nil) 
    end 
    end 

    def check_json_array(value) 
    return false unless value.is_a?(Array) 
    value.each do |item| 
     return false unless item.is_a?(Hash) 
     return false if item[:school].blank? || item[:degree].blank? || !valid_date_time(item[:from_date]) || !valid_date_time(item[:to_date]) 
    end 
    true 
    end 

    def valid_date_time(date) 
    #this needs work as it will pass for instance "Tue" as true, since DateTime will parse even single day initials to the current closest date 
    (DateTime.parse(date) rescue nil) 
    end 
end 
関連する問題