Module: Coroutine::ActsAsLabel::Base::ClassMethods

Defined in:
lib/acts_as_label/base.rb

Instance Method Summary collapse

Instance Method Details

#acts_as_label(options = {}) ⇒ Object

Description

This acts_as extension implements a system label and a friendly label on a class and centralizes the logic for performing validations and accessing items by system label.

Usage

Simple Example

class BillingFrequency < ActiveRecord::Base
  has_many :subscriptions
  acts_as_label :default => :monthly
end

class Subscription < ActiveRecord::Base
  belongs_to :billing_frequency
end

subscription.billing_frequency = BillingFrequency.monthly
subscription.billing_frequency = BillingFrequency.default

STI Example:

class Label < ActiveRecord::Base
  acts_as_label :scoped_to => :type
end

class BillingFrequency < Label
  has_many :subscriptions
  def self.default
    BillingFrequency.monthly
  end
end

class Subscription < ActiveRecord::Base
  belongs_to :billing_frequency
end

subscription.billing_frequency = BillingFrequency.monthly
subscription.billing_frequency = BillingFrequency.default

Configuration

  • system_label_cloumn - specifies the column name to use for storing the system label (default: system_label)

  • label_column - specifies the column name to use for storing the label (default: label)

  • default - specifies the system label value of the default instance (default: the first record in the default scope)



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# File 'lib/acts_as_label/base.rb', line 63

def acts_as_label(options = {})
  
  #-------------------------------------------
  # scrub options
  #-------------------------------------------
  options       = {} unless options.is_a?(Hash)
  system_label  = options.key?(:system_label_column)  ? options[:system_label_column].to_sym  : :system_label
  label         = options.key?(:label_column)         ? options[:label_column].to_sym         : :label
  scope         = options.key?(:scope)                ? options[:scope]                       : "1 = 1"
  default       = options.key?(:default)              ? options[:default].to_sym              : nil
            
  
  #--------------------------------------------
  # mix methods into class definition
  #--------------------------------------------
  class_eval do
    
    # inheritable accessors
    class_attribute :acts_as_label_system_label_column
    class_attribute :acts_as_label_label_column
    class_attribute :acts_as_label_scope
    class_attribute :acts_as_label_default_system_label

    self.acts_as_label_system_label_column  = system_label
    self.acts_as_label_label_column         = label
    self.acts_as_label_scope                = scope
    self.acts_as_label_default_system_label = default

    # protect attributes
    attr_readonly               system_label
    
    # validations
    validates_presence_of       system_label
    validates_length_of         system_label,  :maximum   => 255
    validates_format_of         system_label,  :with      => /^[A-Z][_A-Z0-9]*$/
    validates_presence_of       label
    validates_length_of         label,         :maximum => 255
    
    # This method catches all undefined method calls. It first sees if any ancestor
    # understands the request. If not, it tries to match the method call to an
    # existing system label. If that is found, it lazily manufacturers a method on the
    # class of the same name. Otherwise, it throws the NoMethodError.
    #
    def self.method_missing(method, *args, &block)
      begin
        super
      rescue NoMethodError => e
        if has_acts_as_label_method?(method)
          self.__send__(method)
        else
          throw e
        end
      end
    end
    
                
    # This method determines whether or not the class has an instance with
    # the given system label. If it does, it also lazily creates a method 
    # that can be accessed without all this method missing nonsense.
    #
    def self.has_acts_as_label_method?(method_name)
      mn = method_name.to_s.underscore
      sl = mn.upcase
      
      if record = by_acts_as_label_system_label(sl)
        eval %Q{
          class << self
            def #{mn}
              by_acts_as_label_system_label('#{sl}')
            end
            
            alias_method :#{mn.upcase}, :#{mn}
          end
        }
      end
      
      !!record
    end
    
    
    # This method finds an active record object for the given system label.
    #             
    def self.by_acts_as_label_system_label(system_label)
      where("#{acts_as_label_system_label_column} = ?", system_label.to_s.upcase).first
    end


    # This block adds a class method to return the default record.
    #
    unless self.method_defined? :default
      if default.nil?
        def self.default
          self.first
        end
      else
        def self.default
          self.send("#{acts_as_label_default_system_label}")
        end
      end
    end


    # This method overrides the system label column writer to force 
    # upcasing of the value.
    #
    define_method("#{acts_as_label_system_label_column}=") do |value| 
      value = value.to_s.strip.upcase unless value.nil?
      write_attribute("#{acts_as_label_system_label_column}", value)
    end
                  
    
    # Add all the instance methods
    include Coroutine::ActsAsLabel::Base::InstanceMethods

  end
end