subset_validator

Description

An ActiveModel validation for checking if an attribute's values are a subset of another set.

In other words, check that an array is a subset of another array, a hash is a subset of another hash, etc.

Usage Example

Say you have a User model, and each user can have multiple roles, like this:

class User
  attr_accessor :roles

  @@valid_roles = %w(admin manager developer)

  def initialize(roles)
    raise ArgumentError, 'The roles must be an array.' unless roles.is_a? Array

    @roles = roles
  end
end

You probably want your model to prevent arbitrary roles from being assigned. Eg:

the_boss = User.new %w(admin manager bonehead)

One solution is to write a custom setter method that checks if each element of the roles array is contained in @@valid_roles . That's a pain in the ass, especially if you need to do it more than once.

Enter SubsetValidator:

require 'active_model'
require 'subset_validator'

class User
  include ActiveModel::Validations

  attr_accessor :roles

  @@valid_roles = %w(admin manager developer)

  validates :roles, :subset => {:in => @@valid_roles}

  def initialize(roles)
    raise ArgumentError, 'The roles must be an array.' unless roles.is_a? Array

    @roles = roles
  end
end

That one validation takes care of it all for you:

the_boss = User.new %w(admin manager bonehead)
 => #<User:0x91e4aac @roles=["admin", "manager", "bonehead"]>

the_boss.valid?
 => false
the_boss.errors
 => {:roles=>["contains an invalid value"]}

the_boss.roles = %w(admin manager)
 => ["admin", "manager"]
the_boss.valid?
 => true

SubsetValidator works on more than just arrays, too. In fact, it'll work on anything, provided that:

Contributing to subset_validator

Copyright © 2010 Nick Hoffman. See LICENSE.txt for further details.