aiaio (owner)

Revisions

  • 8896da aiaio Sat Jun 13 16:28:45 -0700 2009
gist: 129471 Download_button fork
public
Public Clone URL: git://gist.github.com/129471.git
interface_for_procs_with_papreclip.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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
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
# Adds behavior for getting, setting, and validating
# images for any given model. Relies on RAILS_ROOT/config/image_definitions.rb
module ImageHandling
 
  def self.included(base)
 
    base.class_eval do
      # Defines accessor names: if the class is Book,
      # names will be #book_images and #book_images=
      image_accessor_name = self.to_s.underscore + "_images"
      
      # Define a getter method for all images.
      define_method(image_accessor_name) do
        self.images
      end
 
      # Define a setter methods for images.
      define_method(image_accessor_name + "=") do |attrs|
        attrs.each do |attr_set|
          if attr_set['id'].blank?
            self.images.create(attr_set)
          else
            image = self.images.find(attr_set['id'])
            image.update_attributes(attr_set)
          end
        end
      end
 
      # Note: Uses the conditional validation plugin to determine whether
      # to run the validation.
      validation_check_name = "should_validate_#{image_accessor_name}?".to_sym
      validate :validate_required_images, :if => validation_check_name
      after_validation :filter_image_errors
    end
 
    base.extend(ClassMethods)
    base.send(:include, InstanceMethods)
  end
 
  module ClassMethods
 
    # Gets the image definitions from RAILS_ROOT/config/image_definitions.rb.
    # Expects a constant named class_name + ImageDefinition.
    # If you only want an array of one of the definitions' attributes,
    # pass in the attribute's name as a symbol (e.g., :label).
    def image_definitions(attr=nil)
      image_definition_const = const_get(self.to_s + "ImageDefinition")
      return image_definition_const if attr.nil?
      image_definition_const.map {|image| image[attr]}
    end
  end
 
  module InstanceMethods
 
    # Return available images by label.
    # If no label is given, return all available images.
    def available_images(label=nil)
      if label.nil?
        all_images = self.images
        self.class.image_definitions(:label).map do |label|
          image_with_label = all_images.detect {|image| image.label == label}
          image_with_label || self.images.new(:label => label)
        end
      else
        self.images.find(:first, :conditions => {:label => label})
      end
    end
 
    private
 
    # Validates the presence of all images marked as
    # required in the class's image definition.
    def validate_required_images
      missing_images = []
      self.class.image_definitions.each do |definition|
        if definition[:required]
          if (image = self.available_images(definition[:label])).nil? || image.new_record?
            missing_images << definition[:label]
          end
        end
      end
      return true if missing_images.blank?
      self.errors.add(:base, "The following required images are missing: #{missing_images.to_sentence}")
    end
 
    # HACK: Problem here is that ActiveRecord
    # automatically invokes a validates_associated callback
    # on new has_many relations, which produces some ugly and
    # unhelpful error messages. This filter removes those messages.
    # TODO: Remove this when a better fix is discovered.
    def filter_image_errors
      copy = self.errors.map do |attr, message|
        [attr, message]
      end
      self.errors.clear
      copy.each do |error|
        unless error.first =~ /image/i
        error.last.each do |e|
          self.errors.add(error.first, e)
        end
        end
      end
    end
 
  end
 
end