Module: AttributeChoices::AttributeChoicesMacro

Defined in:
lib/attribute_choices.rb

Instance Method Summary collapse

Instance Method Details

#attribute_choices(attribute, choices, *args) ⇒ Object

Associate a list of display values for an attribute with a list of discreet values

The arguments are:

  • attribute - The attribute whose values you want to map to display values

  • choices - Either an Array of tupples where the first value of the tupple is the attribute \

    value and the second one is the display value mapping, or a +Hash+ where the key is the \
    attribute value and the value is the display value mapping.
    
  • options - An optional hash of options:

    • :localize - If set to true, then I18n.trasnlate is used to translate the value \

      returned by the +_display+ instance methods as well as translate the display \
      values returned by the +_choices+ class method
      
    • :validate - If set to true, validates_inclusion_of is used to ensure that the attribute \

      only accepts the values passed in with the +choices+
      

For example:

class User < ActiveRecord::Base
  attribute_choices :gender,  { 'm' => "Male", 'f' => 'Female'}
  attribute_choices :age_group,  [
    ['18-24', '18 to 24 years old], 
    ['25-45', '25 to 45 years old']
  ], :localize => true, :validate => false
end

The macro adds an instance method named after the attribute, suffixed with _display (e.g. gender_display for :gender) that returns the display value of the attribute for a given value, or nil if a mapping for a value is missing.

It also adds a class method named after the attribute, suffixed with _choices (e.g. User.gender_choices for :gender) that returns an array of choices and values in a fomrat that is suitable for passing directly to the Rails select_* helpers.

NOTE: You can use a Hash for the choices argument which is converted to an Array. The order of the \ tupples of the resulting Array is only guaranteed to be preserved if you are using Ruby 1.9



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/attribute_choices.rb', line 42

def attribute_choices(attribute, choices, *args)

  assert_valid_attribute(attribute.to_s)

  write_inheritable_hash :attribute_choices_storage, {}
  class_inheritable_reader :attribute_choices_storage

  write_inheritable_hash :attribute_choices_options,  {}
  class_inheritable_reader :attribute_choices_options

  attribute = attribute.to_sym

  options = args.extract_options!
  options.reverse_merge!(:validate => false, :localize => false)
  options.assert_valid_keys(:validate, :localize)
  attribute_choices_options[attribute.to_sym] = options

  if options[:localize]
    attribute_choices_storage[attribute] = choices.to_a.collect {|t| [t.first, I18n.translate(t.last)]}
  else
    attribute_choices_storage[attribute] = choices.to_a
  end

  define_method("#{attribute.to_s}_display") do
    tupple = attribute_choices_storage[attribute].assoc(read_attribute(attribute))
    tupple && tupple.last
  end

  (class << self; self; end).send(:define_method, "#{attribute.to_s}_choices") do
    attribute_choices_storage[attribute].collect(&:reverse)
  end

  if column_names.include?(attribute.to_s) && options[:validate]
    validates_inclusion_of attribute.to_sym, :in => attribute_choices_storage[attribute].collect {|i| i.first}
  end

end