Browse files

MailForm is now the sender. This avoid the need to create subfolders …

…inside mail_form.
  • Loading branch information...
1 parent c2fb45f commit 2aafdce539a465c769022892b9e4dc4342155d64 @josevalim josevalim committed Dec 28, 2009
View
64 lib/mail_form.rb
@@ -1,32 +1,50 @@
require 'active_model'
-require 'mail_form/base'
-require 'mail_form/dsl'
-require 'mail_form/notifier'
-class MailForm
- extend MailForm::DSL
+class MailForm < ActionMailer::Base
+ autoload :DSL, 'mail_form/dsl'
+ autoload :Resource, 'mail_form/resource'
- ACCESSORS = [ :form_attributes, :form_subject, :form_captcha,
- :form_attachments, :form_recipients, :form_sender,
- :form_headers, :form_template, :form_appendable ]
+ self.template_root = File.expand_path('../views', File.dirname(__FILE__))
- DEFAULT_MESSAGES = { :blank => "can't be blank", :invalid => "is invalid" }
+ def default(form)
+ @from = get_from_class_and_eval(form, :form_sender)
+ @subject = get_from_class_and_eval(form, :form_subject)
+ @recipients = get_from_class_and_eval(form, :form_recipients)
+ @template = get_from_class_and_eval(form, :form_template)
- class_inheritable_reader *ACCESSORS
- protected *ACCESSORS
+ raise ScriptError, "You forgot to setup #{form.class.name} recipients" if @recipients.blank?
+ raise ScriptError, "You set :append values but forgot to give me the request object" if form.request.nil? && !form.class.form_appendable.blank?
- # Initialize arrays and hashes
- #
- write_inheritable_array :form_captcha, []
- write_inheritable_array :form_appendable, []
- write_inheritable_array :form_attributes, []
- write_inheritable_array :form_attachments, []
+ @resource = @form = form
+ @sent_on = Time.now.utc
+ @headers = form.class.form_headers
+ @content_type = 'text/html'
- headers({})
- sender {|c| c.email }
- subject{|c| c.class.model_name.human }
- template 'default'
+ form.class.form_attachments.each do |attribute|
+ value = form.send(attribute)
+ if value.respond_to?(:read)
+ attachment value.content_type.to_s do |att|
+ att.filename = value.original_filename
+ att.body = value.read
+ end
+ end
+ end
+ end
+
+ protected
+
+ def get_from_class_and_eval(form, method)
+ duck = form.class.send(method)
+
+ if duck.is_a?(Proc)
+ duck.call(form)
+ elsif duck.is_a?(Symbol)
+ form.send(duck)
+ else
+ duck
+ end
+ end
end
-I18n.load_path.unshift File.expand_path('mail_form/locales/en.yml', File.dirname(__FILE__))
-MailForm::Notifier.template_root = File.expand_path('../views', File.dirname(__FILE__))
+
+I18n.load_path.unshift File.expand_path('mail_form/locales/en.yml', File.dirname(__FILE__))
View
332 lib/mail_form/dsl.rb
@@ -1,183 +1,179 @@
-class MailForm
- module DSL
+module MailForm::DSL
- protected
+ # Declare your form attributes. All attributes declared here will be appended
+ # to the e-mail, except the ones captcha is true.
+ #
+ # == Options
+ #
+ # * <tt>:validate</tt> - When true, validates the attributes can't be blank.
+ # When a regexp is given, check if the attribute matches is not blank and
+ # then if it matches the regexp.
+ #
+ # Whenever :validate is a symbol, the method given as symbol will be
+ # called. You can then 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 :message
+ # attributes :type
+ # 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!
- # Declare your form attributes. All attributes declared here will be appended
- # to the e-mail, except the ones captcha is true.
- #
- # == Options
- #
- # * <tt>:validate</tt> - When true, validates the attributes can't be blank.
- # When a regexp is given, check if the attribute matches is not blank and
- # then if it matches the regexp.
- #
- # Whenever :validate is a symbol, the method given as symbol will be
- # called. You can then 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 :message
- # attributes :type
- # 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
- attr_accessor *accessors
+ if options[:attachment]
+ write_inheritable_array(:form_attachments, accessors)
+ elsif options[:captcha]
+ write_inheritable_array(:form_captcha, accessors)
+ else
+ write_inheritable_array(:form_attributes, accessors)
+ end
- if options[:attachment]
- write_inheritable_array(:form_attachments, accessors)
- elsif options[:captcha]
- write_inheritable_array(:form_captcha, accessors)
- else
- write_inheritable_array(:form_attributes, accessors)
- end
+ validation = options.delete(:validate)
+ return unless validation
- validation = options.delete(:validate)
- return unless validation
-
- accessors.each do |accessor|
- case validation
- when Symbol, Class
- validate validation
- return
- 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
+ accessors.each do |accessor|
+ case validation
+ when Symbol, Class
+ validate validation
+ return
+ 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
- alias :attributes :attribute
- # Declares contact email sender. It can be a string or a proc or a symbol.
- #
- # When a symbol is given, it will call a method on the form object with
- # the same name as the symbol. As a proc, it receives a simple form
- # instance. By default is the class human name.
- #
- # == Examples
- #
- # class ContactForm < MailForm
- # subject "My Contact Form"
- # end
- #
- def subject(duck=nil, &block)
- write_inheritable_attribute(:form_subject, duck || block)
- end
+ validates_presence_of accessor unless options[:allow_blank] == true
+ end
+ end
+ alias :attributes :attribute
- # Declares contact email sender. It can be a string or a proc or a symbol.
- #
- # When a symbol is given, it will call a method on the form object with
- # the same name as the symbol. As a proc, it receives a simple form
- # instance. By default is:
- #
- # sender{ |c| c.email }
- #
- # This requires that your MailForm object have an email attribute.
- #
- # == Examples
- #
- # class ContactForm < MailForm
- # # Change sender to include also the name
- # sender { |c| %{"#{c.name}" <#{c.email}>} }
- # end
- #
- def sender(duck=nil, &block)
- write_inheritable_attribute(:form_sender, duck || block)
- end
- alias :from :sender
+ # Declares contact email sender. It can be a string or a proc or a symbol.
+ #
+ # When a symbol is given, it will call a method on the form object with
+ # the same name as the symbol. As a proc, it receives a simple form
+ # instance. By default is the class human name.
+ #
+ # == Examples
+ #
+ # class ContactForm < MailForm
+ # subject "My Contact Form"
+ # end
+ #
+ def subject(duck=nil, &block)
+ write_inheritable_attribute(:form_subject, duck || block)
+ end
- # Who will receive the e-mail. Can be a string or array or a symbol or a proc.
- #
- # When a symbol is given, it will call a method on the form object with
- # the same name as the symbol. As a proc, it receives a simple form instance.
- #
- # Both the proc and the symbol must return a string or an array. By default
- # is nil.
- #
- # == Examples
- #
- # class ContactForm < MailForm
- # recipients [ "first.manager@domain.com", "second.manager@domain.com" ]
- # end
- #
- def recipients(duck=nil, &block)
- write_inheritable_attribute(:form_recipients, duck || block)
- end
- alias :to :recipients
+ # Declares contact email sender. It can be a string or a proc or a symbol.
+ #
+ # When a symbol is given, it will call a method on the form object with
+ # the same name as the symbol. As a proc, it receives a simple form
+ # instance. By default is:
+ #
+ # sender{ |c| c.email }
+ #
+ # This requires that your MailForm object have an email attribute.
+ #
+ # == Examples
+ #
+ # class ContactForm < MailForm
+ # # Change sender to include also the name
+ # sender { |c| %{"#{c.name}" <#{c.email}>} }
+ # end
+ #
+ def sender(duck=nil, &block)
+ write_inheritable_attribute(:form_sender, duck || block)
+ end
+ alias :from :sender
- # Additional headers to your e-mail.
- #
- # == Examples
- #
- # class ContactForm < MailForm
- # headers { :content_type => 'text/html' }
- # end
- #
- def headers(hash)
- write_inheritable_hash(:form_headers, hash)
- end
+ # Who will receive the e-mail. Can be a string or array or a symbol or a proc.
+ #
+ # When a symbol is given, it will call a method on the form object with
+ # the same name as the symbol. As a proc, it receives a simple form instance.
+ #
+ # Both the proc and the symbol must return a string or an array. By default
+ # is nil.
+ #
+ # == Examples
+ #
+ # class ContactForm < MailForm
+ # recipients [ "first.manager@domain.com", "second.manager@domain.com" ]
+ # end
+ #
+ def recipients(duck=nil, &block)
+ write_inheritable_attribute(:form_recipients, duck || block)
+ end
+ alias :to :recipients
- # Customized template for your e-mail, if you don't want to use default
- # 'contact' template or need more than one contact form with different
- # template layouts.
- #
- # When a symbol is given, it will call a method on the form object with
- # the same name as the symbol. As a proc, it receives a simple form
- # instance. Both method and proc must return a string with the template
- # name. Defaults to 'contact'.
- #
- # == Examples
- #
- # class ContactForm < MailForm
- # # look for a template in views/mail_form/notifier/my_template.erb
- # template 'my_template'
- # end
- #
- def template(new_template)
- write_inheritable_attribute(:form_template, new_template)
- end
+ # Additional headers to your e-mail.
+ #
+ # == Examples
+ #
+ # class ContactForm < MailForm
+ # headers { :content_type => 'text/html' }
+ # end
+ #
+ def headers(hash)
+ write_inheritable_hash(:form_headers, hash)
+ end
- # 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)
- write_inheritable_array(:form_appendable, values)
- end
+ # Customized template for your e-mail, if you don't want to use default
+ # 'contact' template or need more than one contact form with different
+ # template layouts.
+ #
+ # When a symbol is given, it will call a method on the form object with
+ # the same name as the symbol. As a proc, it receives a simple form
+ # instance. Both method and proc must return a string with the template
+ # name. Defaults to 'contact'.
+ #
+ # == Examples
+ #
+ # class ContactForm < MailForm
+ # # look for a template in views/mail_form/notifier/my_template.erb
+ # template 'my_template'
+ # end
+ #
+ def template(new_template)
+ write_inheritable_attribute(:form_template, new_template)
+ end
+ # 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)
+ write_inheritable_array(:form_appendable, values)
end
+
end
View
46 lib/mail_form/notifier.rb
@@ -1,46 +0,0 @@
-# This is the class responsable to send the e-mails.
-#
-class MailForm
- class Notifier < ActionMailer::Base
-
- def contact(form)
- @from = get_from_class_and_eval(form, :form_sender)
- @subject = get_from_class_and_eval(form, :form_subject)
- @recipients = get_from_class_and_eval(form, :form_recipients)
- @template = get_from_class_and_eval(form, :form_template)
-
- raise ScriptError, "You forgot to setup #{form.class.name} recipients" if @recipients.blank?
- raise ScriptError, "You set :append values but forgot to give me the request object" if form.request.nil? && !form.class.form_appendable.blank?
-
- @form = form
- @sent_on = Time.now.utc
- @headers = form.class.form_headers
- @content_type = 'text/html'
-
- form.class.form_attachments.each do |attribute|
- value = form.send(attribute)
- if value.respond_to?(:read)
- attachment value.content_type.to_s do |att|
- att.filename = value.original_filename
- att.body = value.read
- end
- end
- end
- end
-
- protected
-
- def get_from_class_and_eval(form, method)
- duck = form.class.send(method)
-
- if duck.is_a?(Proc)
- duck.call(form)
- elsif duck.is_a?(Symbol)
- form.send(duck)
- else
- duck
- end
- end
-
- end
-end
View
25 lib/mail_form/base.rb → lib/mail_form/resource.rb
@@ -1,9 +1,30 @@
-class MailForm
+class MailForm::Resource
extend ActiveModel::Naming
extend ActiveModel::Translation
include ActiveModel::Validations
include ActiveModel::Conversion
+ extend MailForm::DSL
+
+ ACCESSORS = [ :form_attributes, :form_subject, :form_captcha,
+ :form_attachments, :form_recipients, :form_sender,
+ :form_headers, :form_template, :form_appendable ]
+
+ class_inheritable_reader *ACCESSORS
+ protected *ACCESSORS
+
+ # Initialize arrays and hashes
+ #
+ write_inheritable_array :form_captcha, []
+ write_inheritable_array :form_appendable, []
+ write_inheritable_array :form_attributes, []
+ write_inheritable_array :form_attachments, []
+
+ headers({})
+ sender {|c| c.email }
+ subject{|c| c.class.model_name.human }
+ template 'default'
+
attr_accessor :request
# Initialize assigning the parameters given as hash (just as in ActiveRecord).
@@ -60,7 +81,7 @@ def id
#
def deliver(run_validations=true)
if !run_validations || (self.not_spam? && self.valid?)
- MailForm::Notifier.deliver_contact(self)
+ MailForm.deliver_default(self)
return true
else
return false
View
6 test/notifier_test.rb
@@ -170,12 +170,12 @@ def test_form_with_file_does_not_output_attachment_as_attribute
def test_form_with_customized_template_render_correct_template
begin
- default_template_root = MailForm::Notifier.template_root
- MailForm::Notifier.template_root = File.join(File.dirname(__FILE__), 'views')
+ default_template_root = MailForm.template_root
+ MailForm.template_root = File.join(File.dirname(__FILE__), 'views')
@template.deliver
assert_match 'Hello from my cystom template!', ActionMailer::Base.deliveries.last.body
ensure
- MailForm::Notifier.template_root = default_template_root
+ MailForm.template_root = default_template_root
end
end
View
4 test/test_helper.rb
@@ -15,7 +15,7 @@
$:.unshift File.dirname(__FILE__) + '/../lib'
require 'mail_form'
-class ContactForm < MailForm
+class ContactForm < MailForm::Resource
recipients 'my.email@my.domain.com'
attribute :name, :validate => true
@@ -50,7 +50,7 @@ def set_recipient
end
end
-class NullRecipient < MailForm
+class NullRecipient < MailForm::Resource
sender 'my.email@my.domain.com'
end
View
0 ...ws/mail_form/notifier/custom_template.erb → test/views/mail_form/custom_template.erb
File renamed without changes.
View
0 views/mail_form/notifier/default.erb → views/mail_form/default.erb
File renamed without changes.

0 comments on commit 2aafdce

Please sign in to comment.