Skip to content
This repository
tree: 5e815e1b87
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 151 lines (134 sloc) 4.982 kb
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 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
module MailForm
  module Delivery
    extend ActiveSupport::Concern

    included do
      class_attribute :mail_attributes
      self.mail_attributes = []

      class_attribute :mail_captcha
      self.mail_captcha = []

      class_attribute :mail_attachments
      self.mail_attachments = []

      class_attribute :mail_appendable
      self.mail_appendable = []

      if respond_to?(:before_deliver) && respond_to?(:after_deliver)
        before_deliver :not_spam?
        after_deliver :deliver!
      else # For ActiveRecord compatibility
        before_create :not_spam?
        after_create :deliver!
        alias :deliver :save
      end

      attr_accessor :request
    end

    module ClassMethods
      # Declare your form attributes. All attributes declared here will be appended
      # to the e-mail, except the ones captcha is true.
      #
      # == Options
      #
      # * :validate - A hook to validates_*_of. When true is given, validates the
      # presence of the attribute. When a regexp, validates format. When array,
      # validates the inclusion of the attribute in the array.
      #
      # Whenever :validate is given, the presence is automatically checked. Give
      # :allow_blank => true to override.
      #
      # Finally, when :validate is a symbol, the method given as symbol will be
      # called. Then you can add validations as you do in ActiveRecord (errors.add).
      #
      # * <tt>:attachment</tt> - When given, expects a file to be sent and attaches
      # it to the e-mail. Don't forget to set your form to multitype.
      #
      # * <tt>:captcha</tt> - When true, validates the attributes must be blank
      # This is a simple way to avoid spam
      #
      # == Examples
      #
      # class ContactForm < MailForm
      # attributes :name, :validate => true
      # attributes :email, :validate => /^([^@]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
      # attributes :type, :validate => ["General", "Interface bug"]
      # attributes :message
      # attributes :screenshot, :attachment => true, :validate => :interface_bug?
      # attributes :nickname, :captcha => true
      #
      # def interface_bug?
      # if type == 'Interface bug' && screenshot.nil?
      # self.errors.add(:screenshot, "can't be blank when you are reporting an interface bug")
      # end
      # end
      # end
      #
      def attribute(*accessors)
        options = accessors.extract_options!
        attr_accessor *(accessors - instance_methods.map(&:to_sym))

        if options[:attachment]
          self.mail_attachments += accessors
        elsif options[:captcha]
          self.mail_captcha += accessors
        else
          self.mail_attributes += accessors
        end

        validation = options.delete(:validate)
        return unless validation

        accessors.each do |accessor|
          case validation
          when Symbol, Class
            validate validation
            break
          when Regexp
            validates_format_of accessor, :with => validation, :allow_blank => true
          when Array
            validates_inclusion_of accessor, :in => validation, :allow_blank => true
          when Range
            validates_length_of accessor, :within => validation, :allow_blank => true
          end

          validates_presence_of accessor unless options[:allow_blank] == true
        end
      end
      alias :attributes :attribute

      # Values from request object to be appended to the contact form.
      # Whenever used, you have to send the request object when initializing the object:
      #
      # @contact_form = ContactForm.new(params[:contact_form], request)
      #
      # You can get the values to be appended from the AbstractRequest
      # documentation (http://api.rubyonrails.org/classes/ActionController/AbstractRequest.html)
      #
      # == Examples
      #
      # class ContactForm < MailForm
      # append :remote_ip, :user_agent, :session, :cookies
      # end
      #
      def append(*values)
        self.mail_appendable += values
      end
    end

    # In development, raises an error if the captcha field is not blank. This is
    # is good to remember that the field should be hidden with CSS and shown only
    # to robots.
    #
    # In test and in production, it returns true if all captcha fields are blank,
    # returns false otherwise.
    #
    def spam?
      self.class.mail_captcha.each do |field|
        next if send(field).blank?

        if defined?(Rails) && Rails.env.development?
          raise ScriptError, "The captcha field #{field} was supposed to be blank"
        else
          return true
        end
      end

      false
    end

    def not_spam?
      !spam?
    end

    # Deliver the resource without running any validation.
    def deliver!
      MailForm::Notifier.contact(self).deliver
    end
  end
end
Something went wrong with that request. Please try again.