Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate inclusion of array content in rails

Hi I have an array column in my model:

t.text :sphare, array: true, default: []

And I want to validate that it includes only the elements from the list ("Good", "Bad", "Neutral")

My first try was:

 validates_inclusion_of :sphare, in: [ ["Good"], ["Bad"], ["Neutral"] ]

But when I wanted to create objects with more then one value in sphare ex(["Good", "Bad"] the validator cut it to just ["Good"].

My question is:

How to write a validation that will check only the values of the passed array, without comparing it to fix examples?

Edit added part of my FactoryGirl and test that failds:

Part of my FactoryGirl:

sphare ["Good", "Bad"]

and my rspec test:

  it "is not valid with wrong sphare" do
    expect(build(:skill, sphare: ["Alibaba"])).to_not be_valid
  end
 it "is valid with proper sphare" do
    proper_sphare = ["Good", "Bad", "Neutral"]
    expect(build(:skill, sphare: [proper_sphare.sample])).to be_valid
  end  
like image 844
Kazik Avatar asked Oct 05 '15 04:10

Kazik


People also ask

What is inclusion in rails?

2.7 inclusionThis helper validates that the attributes' values are included in a given set. In fact, this set can be any enumerable object. class Coffee < ApplicationRecord validates :size, inclusion: { in: %w(small medium large), message: "%{value} is not a valid size" } end Copy.

What is validate in rails?

In Rails, validations are used in order to ensure valid data is passed into the database. Validations can be used, for example, to make sure a user inputs their name into a name field or a username is unique.

Can we save an object in DB if its validations do not pass?

If any validations fail, the object will be marked as invalid and Active Record will not perform the INSERT or UPDATE operation. This helps to avoid storing an invalid object in the database. You can choose to have specific validations run when an object is created, saved, or updated.


2 Answers

Do it this way:

validates :sphare, inclusion: { in: ["Good", "Bad", "Neutral"] }

or, you can be fancy by using the short form of creating the array of strings: %w(Good Bad Neutral):

validates :sphare, inclusion: { in: %w(Good Bad Neutral) }

See the Rails Documentation for more usage and example of inclusion.

Update

As the Rails built-in validator does not fit your requirement, you can add a custom validator in your model like following:

validate :correct_sphare_types

private

def correct_sphare_types
  if self.sphare.blank?
    errors.add(:sphare, "sphare is blank/invalid")
  elsif self.sphare.detect { |s| !(%w(Good Bad Neutral).include? s) }
    errors.add(:sphare, "sphare is invalid")
  end
end
like image 173
K M Rakibul Islam Avatar answered Oct 26 '22 03:10

K M Rakibul Islam


You can implement your own ArrayInclusionValidator:

# app/validators/array_inclusion_validator.rb
class ArrayInclusionValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    # your code here

    record.errors.add(attribute, "#{attribute_name} is not included in the list")
  end
end

In the model it looks like this:

# app/models/model.rb
class YourModel < ApplicationRecord
  ALLOWED_TYPES = %w[one two three]
  validates :type_of_anything, array_inclusion: { in: ALLOWED_TYPES }
end

Examples can be found here:

  • https://github.com/sciencehistory/kithe/blob/master/app/validators/array_inclusion_validator.rb
  • https://gist.github.com/bbugh/fadf8c65b7f4d3eaa55e64acfc563ab2
like image 25
mikeoleynik Avatar answered Oct 26 '22 03:10

mikeoleynik