Search code examples
ruby-on-railsvalidation

Built-in Rails way of validating that a PostgreSQL Array[String] field has at least one item in it?


We have a PostgreSQL array string field basically like:

add_column :books, :tags, :string, array: true, default: []

How can I add a validation to verify that that tags array has at least 1 string in it, and that the string is from an enum set of strings?

I see we have accept on string values, like this:

class Person < ApplicationRecord
  validates :terms_of_service, acceptance: { accept: 'yes' }
  validates :eula, acceptance: { accept: ['TRUE', 'accepted'] }
end

But what about on array[string] fields? Is something like this my best option?

class Book < ApplicationRecord
  # tags :string is an Array
  validate :tags_has_one_from_set

  enum tag: {
    foo: 'foo',
    bar: 'bar'
  }

  def tags_has_one_from_set
    allowed_tags = Book.tags.values

    if tags.length == 0
      errors.add(:tags, "Must select at least one tag")
    elsif !tags.all? { |t| allowed_tags.include?(t) }
      errors.add(:tags, "Must select from approved tag list")
    end
  end
end

Is there any more "built-in" or best-practice sort of way of doing this in Rails?


Solution

  • You should be able to use the built in length and inclusion validators:

    validates :tags,
      length: { minimum: 1, message: "must have at least one tag" },
      inclusion: { in: tags.values, message: "must be selected from: #{tags.values.join ", "}" }