4

I use acts-as-taggable-on gem to populate a user interests on a User model like this

# User.rb
acts_as_taggable
acts_as_taggable_on :interests

As I populate the interest_list array, I need to check that the given values matches against a constant array to make sure these are accepted values, something like this

VALID_INTERESTS = ["music","biking","hike"]
validates :interest_list, :inclusion => { :in => VALID_INTERESTS, :message => "%{value} is not a valid interest" }

The code above returns the following error

@user = User.new
@user.interest_list = ["music","biking"]
@user.save
=> false …. @messages={:interest_list=>["music, biking is not a valid interest"]}

I can see the inclusion doesn't realize it should iterate over the array elements instead of s considering as a plain string but I'm not sure how to achieve this. Any idea?

1
  • 1
    This has been changed in Rails to work as you described it: github.com/rails/rails/commit/… The answers below should no longer be necessary in most cases. Commented Sep 26, 2022 at 23:53

3 Answers 3

13

The standard inclusion validator will not work for this use case, since it checks that the attribute in question is a member of a given array. What you want is to check that every element of an array (the attribute) is a member of a given array.

To do this you could create a custom validator, something like this:

VALID_INTERESTS = ["music","biking","hike"]
validate :validate_interests

private

def validate_interests
  if (invalid_interests = (interest_list - VALID_INTERESTS))
    invalid_interests.each do |interest|
      errors.add(:interest_list, interest + " is not a valid interest")
    end
  end
end

I'm getting the elements of interest_list not in VALID_INTERESTS by taking the difference of these two arrays.

I haven't actually tried this code so can't guarantee it will work, but the solution I think will look something like this.

Sign up to request clarification or add additional context in comments.

1 Comment

This is a quite common pattern, surprising I wasn't able to find (quickly) the gem to do this.
0

It's a nice implementation, but I forget about one in the description of the model.

serialize : interest_list, Array

1 Comment

Welcome to Stack Overflow! Please take the tour, look around, and read through the Help Center. For single line answers, please use comments instead of creating a new answer.
0

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:

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.