josevalim-simple_form 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG CHANGED
@@ -1,3 +1,5 @@
1
+ * Added support to :attachments (thanks to @andrewtimberlake)
2
+
1
3
  # Version 0.1
2
4
 
3
5
  * First release
data/README CHANGED
@@ -17,12 +17,12 @@ to have a contact form (including the e-mail):
17
17
  recipients "your.email@your.domain.com"
18
18
  sender{|c| %{"#{c.name}" <#{c.email}>} }
19
19
 
20
- attribute :name, :validate => true
21
- attribute :email, :validate => /[^@]+@[^\.]+\.[\w\.\-]+/
22
- attribute :company_name
23
- attribute :telephone
24
- attribute :message, :validate => true
25
- attribute :nickname, :captcha => true
20
+ attribute :name, :validate => true
21
+ attribute :email, :validate => /[^@]+@[^\.]+\.[\w\.\-]+/
22
+ attribute :file, :attachment => true
23
+
24
+ attribute :message
25
+ attribute :nickname, :captcha => true
26
26
  end
27
27
 
28
28
  Then you start a script/console and type:
@@ -32,8 +32,11 @@ Then you start a script/console and type:
32
32
 
33
33
  Check your inbox and the e-mail will be there, with the sent fields.
34
34
 
35
- SimpleForm is tested and compatible with Rails 2.2.x and Rails 2.3.x. It also
36
- supports I18n and error messages, just as an ActiveRecord model does.
35
+ SimpleForm also support attachments, I18n, error messages like in ActiveRecord
36
+ (so it works with custom FormBuilders) and can also send the user request information
37
+ in the contact mail.
38
+
39
+ It's tested and compatible with Rails 2.2.x and Rails 2.3.x.
37
40
 
38
41
  Installation
39
42
  ------------
@@ -47,6 +50,25 @@ If you want it as plugin, just do:
47
50
 
48
51
  script/plugin install git://github.com/josevalim/simple_form.git
49
52
 
53
+ Request
54
+ -------
55
+
56
+ SimpleForm makes easy to append user information to the contact mail. You just
57
+ have to do:
58
+
59
+ class ContactForm < SimpleForm
60
+ append :remote_ip, :user_agent, :session
61
+ # ...
62
+ end
63
+
64
+ And in your controller:
65
+
66
+ @contact_form = ContactForm.new(params[:contact_form], request)
67
+
68
+ And the remote ip, user agent and session will be sent in the e-mail in a
69
+ request information session. You can send to append any method that the
70
+ request object responds to.
71
+
50
72
  API Overview
51
73
  ------------
52
74
 
@@ -61,6 +83,9 @@ Options:
61
83
  When a regexp is given, check if the attribute matches is not blank and
62
84
  then if it matches the regexp.
63
85
 
86
+ * :attachment - When given, expects a file to be sent and attaches
87
+ it to the e-mail. Don't forget to set your form to multitype.
88
+
64
89
  * :captcha - When true, validates the attributes must be blank.
65
90
  This is a simple way to avoid spam and the input should be hidden with CSS.
66
91
 
@@ -109,9 +134,9 @@ This requires that your SimpleForm object have at least an email attribute.
109
134
 
110
135
  Additional headers to your e-mail.
111
136
 
112
- == recipients(string_or_array)
137
+ == recipients(string_or_array_or_proc)
113
138
 
114
- Who will receive the e-mail. Can be a string or array.
139
+ Who will receive the e-mail. Can be a string or array, or a proc that returns one of them.
115
140
 
116
141
  I18n
117
142
  ----
@@ -121,17 +146,24 @@ Below is an I18n example file:
121
146
 
122
147
  simple_form:
123
148
  models:
124
- contact_form: Formulário de contato
149
+ contact_form: "Your site contact form"
125
150
  attributes:
126
- name: Nome
127
- email: E-mail
128
- company_name: Empresa
129
- telephone: Telefone
130
- message: Mensagem
151
+ email: "E-mail"
152
+ telephone: "Telephone number"
153
+ message: "Sent message"
131
154
  messages:
132
- blank: "não pode ficar em branco"
133
- invalid: "não é válido"
134
- telephone: "deve haver oito dígitos"
155
+ blank: "can not be blank"
156
+ invalid: "is not valid"
157
+ telephone: "must have eight digits"
158
+ request:
159
+ title: "Technical information about the user"
160
+ remote_ip: "IP Address"
161
+ user_agent: "Browser"
162
+
163
+ Contributors
164
+ ------------
165
+
166
+ * "Andrew Timberlake":http://github.com/andrewtimberlake
135
167
 
136
168
  Bugs and Feedback
137
169
  -----------------
@@ -1,8 +1,13 @@
1
1
  class SimpleForm
2
+ attr_accessor :request
2
3
 
3
4
  # Initialize assigning the parameters given as hash (just as in ActiveRecord).
4
5
  #
5
- def initialize(params={})
6
+ # It also accepts the request object as second parameter which must be sent
7
+ # whenever :append is called.
8
+ #
9
+ def initialize(params={}, request=nil)
10
+ @request = request
6
11
  params.each_pair do |attr, value|
7
12
  self.send(:"#{attr}=", value)
8
13
  end unless params.blank?
@@ -70,8 +75,8 @@ class SimpleForm
70
75
  # If is not spam and the form is valid, we send the e-mail and returns true.
71
76
  # Otherwise returns false.
72
77
  #
73
- def deliver
74
- if self.not_spam? && self.valid?
78
+ def deliver(run_validations=true)
79
+ if !run_validations || (self.not_spam? && self.valid?)
75
80
  SimpleForm::Notifier.deliver_contact(self)
76
81
  return true
77
82
  else
@@ -11,6 +11,10 @@ class SimpleForm
11
11
  # * <tt>:validate</tt> - When true, validates the attributes can't be blank.
12
12
  # When a regexp is given, check if the attribute matches is not blank and
13
13
  # then if it matches the regexp.
14
+ #
15
+ # * <tt>:attachment</tt> - When given, expects a file to be sent and attaches
16
+ # it to the e-mail. Don't forget to set your form to multitype.
17
+ #
14
18
  # * <tt>:captcha</tt> - When true, validates the attributes must be blank
15
19
  # This is a simple way to avoid spam
16
20
  #
@@ -20,6 +24,7 @@ class SimpleForm
20
24
  # attributes :name, :validate => true
21
25
  # attributes :email, :validate => /^([^@]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
22
26
  # attributes :message
27
+ # attributes :file, :attachment => true
23
28
  # attributes :nickname, :captcha => true
24
29
  # end
25
30
  #
@@ -28,7 +33,9 @@ class SimpleForm
28
33
 
29
34
  attr_accessor *accessors
30
35
 
31
- if options[:captcha]
36
+ if options[:attachment]
37
+ write_inheritable_array(:form_attachments, accessors)
38
+ elsif options[:captcha]
32
39
  write_inheritable_array(:form_captcha, accessors)
33
40
  else
34
41
  write_inheritable_array(:form_attributes, accessors)
@@ -96,10 +103,28 @@ class SimpleForm
96
103
  # recipients "jose.valim@gmail.com"
97
104
  # end
98
105
  #
99
- def recipients(string_or_array)
100
- write_inheritable_array(:form_recipients, [*string_or_array])
106
+ def recipients(string_or_array_or_proc)
107
+ write_inheritable_attribute(:form_recipients, string_or_array_or_proc)
101
108
  end
102
109
  alias :to :recipients
103
110
 
111
+ # Values from request object to be appended to the contact form.
112
+ # Whenever used, you have to send the request object when initializing the object:
113
+ #
114
+ # @contact_form = ContactForm.new(params[:contact_form], request)
115
+ #
116
+ # You can get the values to be appended from the AbstractRequest
117
+ # documentation (http://api.rubyonrails.org/classes/ActionController/AbstractRequest.html)
118
+ #
119
+ # == Examples
120
+ #
121
+ # class ContactForm < SimpleForm
122
+ # append :remote_ip, :user_agent, :session, :cookies
123
+ # end
124
+ #
125
+ def append(*values)
126
+ write_inheritable_array(:form_appendable, values)
127
+ end
128
+
104
129
  end
105
130
  end
@@ -2,16 +2,14 @@
2
2
  #
3
3
  class SimpleForm
4
4
  class Notifier < ActionMailer::Base
5
- def contact(form)
6
- @subject = form.class.form_subject
7
- @subject = @subject.call(form) if @subject.is_a?(Proc)
8
-
9
- @from = form.class.form_sender
10
- @from = @from.call(form) if @from.is_a?(Proc)
11
5
 
12
- @recipients = form.class.form_recipients
6
+ def contact(form)
7
+ @from = get_from_class_and_eval(form, :form_sender)
8
+ @subject = get_from_class_and_eval(form, :form_subject)
9
+ @recipients = get_from_class_and_eval(form, :form_recipients)
13
10
 
14
11
  raise ScriptError, "You forgot to setup #{form.class.name} recipients" if @recipients.blank?
12
+ raise ScriptError, "You set :append values but forgot to give me the request object" if form.request.nil? && !form.class.form_appendable.blank?
15
13
 
16
14
  @body['form'] = form
17
15
  @body['subject'] = @subject
@@ -19,6 +17,29 @@ class SimpleForm
19
17
  @sent_on = Time.now.utc
20
18
  @headers = form.class.form_headers
21
19
  @content_type = 'text/html'
20
+
21
+ form.class.form_attachments.each do |attribute|
22
+ value = form.send(attribute)
23
+ if value.respond_to?(:read)
24
+ attachment value.content_type.to_s do |att|
25
+ att.filename = value.original_filename
26
+ att.body = value.read
27
+ end
28
+ end
29
+ end
22
30
  end
31
+
32
+ protected
33
+
34
+ def get_from_class_and_eval(form, method)
35
+ duck = form.class.send(method)
36
+
37
+ if duck.is_a?(Proc)
38
+ duck.call(form)
39
+ else
40
+ duck
41
+ end
42
+ end
43
+
23
44
  end
24
45
  end
data/lib/simple_form.rb CHANGED
@@ -7,22 +7,24 @@ require File.join(dir, 'simple_form', 'notifier')
7
7
  class SimpleForm
8
8
  extend SimpleForm::DSL
9
9
 
10
- ACCESSORS = [ :form_attributes, :form_validatable, :form_subject,
11
- :form_recipients, :form_sender, :form_captcha, :form_headers ]
10
+ ACCESSORS = [ :form_attributes, :form_validatable, :form_subject, :form_attachments,
11
+ :form_recipients, :form_sender, :form_captcha, :form_headers, :form_appendable ]
12
12
 
13
13
  DEFAULT_MESSAGES = { :blank => "can't be blank", :invalid => "is invalid" }
14
14
 
15
15
  class_inheritable_reader *ACCESSORS
16
16
  protected *ACCESSORS
17
17
 
18
- # Configure default values
18
+ # Initialize arrays and hashes
19
19
  #
20
- attribute :captcha => true
21
- attribute :validate => true
20
+ write_inheritable_array :form_captcha, []
21
+ write_inheritable_array :form_appendable, []
22
+ write_inheritable_array :form_attributes, []
23
+ write_inheritable_array :form_attachments, []
24
+ write_inheritable_hash :form_validatable, {}
22
25
 
23
26
  headers({})
24
- recipients([])
25
- sender{|c| c.email }
27
+ sender {|c| c.email }
26
28
  subject{|c| c.class.human_name }
27
29
  end
28
30
 
data/test/errors_test.rb CHANGED
@@ -47,7 +47,8 @@ class SimpleFormErrorsTest < ActiveSupport::TestCase
47
47
  form = ContactForm.new(:email => 'not_valid')
48
48
  form.valid?
49
49
 
50
- assert_equal ["Name can't be blank", "Email is invalid"], form.errors.full_messages
50
+ assert form.errors.full_messages.include?("Name can't be blank")
51
+ assert form.errors.full_messages.include?("Email is invalid")
51
52
  end
52
53
 
53
54
  def test_full_localized_messages
@@ -56,7 +57,8 @@ class SimpleFormErrorsTest < ActiveSupport::TestCase
56
57
  form = ContactForm.new(:email => 'not_valid')
57
58
  form.valid?
58
59
 
59
- assert_equal ["Name should be filled", "E-mail is not valid"], form.errors.full_messages
60
+ assert form.errors.full_messages.include?("Name should be filled")
61
+ assert form.errors.full_messages.include?("E-mail is not valid")
60
62
  end
61
63
 
62
64
  def teardown
@@ -3,8 +3,15 @@ require File.dirname(__FILE__) + '/test_helper'
3
3
  class SimpleFormNotifierTest < ActiveSupport::TestCase
4
4
 
5
5
  def setup
6
- @form = ContactForm.new(:name => 'José', :email => 'my.email@my.domain.com', :message => 'Cool')
7
- @advanced = AdvancedForm.new(:name => 'José', :email => 'my.email@my.domain.com', :message => "Cool\nno?")
6
+ @form = ContactForm.new(:name => 'José', :email => 'my.email@my.domain.com', :message => 'Cool')
7
+
8
+ @request = ActionController::TestRequest.new
9
+ @valid_attributes = { :name => 'José', :email => 'my.email@my.domain.com', :message => "Cool\nno?" }
10
+ @advanced = AdvancedForm.new(@valid_attributes, @request)
11
+
12
+ test_file = ActionController::TestUploadedFile.new(File.join(File.dirname(__FILE__), 'test-file.txt'))
13
+ @with_file = FileForm.new(:name => 'José', :email => 'my.email@my.domain.com', :message => "Cool", :file => test_file)
14
+
8
15
  ActionMailer::Base.deliveries = []
9
16
  end
10
17
 
@@ -41,7 +48,7 @@ class SimpleFormNotifierTest < ActiveSupport::TestCase
41
48
 
42
49
  def test_recipients_is_an_array
43
50
  @advanced.deliver
44
- assert_equal ['my.email@my.domain.com', 'my.first@email.com', 'my.second@email.com'], ActionMailer::Base.deliveries.first.to
51
+ assert_equal ['my.first@email.com', 'my.second@email.com'], ActionMailer::Base.deliveries.first.to
45
52
  end
46
53
 
47
54
  def test_headers_is_a_hash
@@ -69,10 +76,10 @@ class SimpleFormNotifierTest < ActiveSupport::TestCase
69
76
  end
70
77
 
71
78
  def test_body_contains_localized_attributes_names
72
- I18n.backend.store_translations(:en, :simple_form => { :attributes => { :email => 'E-mail', :message => 'Sent message' } })
79
+ I18n.backend.store_translations(:en, :simple_form => { :attributes => { :message => 'Sent message' } })
73
80
  @form.deliver
74
- assert_match /E\-mail:/, ActionMailer::Base.deliveries.first.body
75
81
  assert_match /Sent message:/, ActionMailer::Base.deliveries.first.body
82
+ assert_no_match /Message:/, ActionMailer::Base.deliveries.first.body
76
83
  end
77
84
 
78
85
  def test_body_simple_format_messages_with_break_line
@@ -83,6 +90,69 @@ class SimpleFormNotifierTest < ActiveSupport::TestCase
83
90
  assert_match /<p>Cool/, ActionMailer::Base.deliveries.last.body
84
91
  end
85
92
 
93
+ def test_body_does_not_append_request_if_append_is_not_called
94
+ @form.deliver
95
+ assert_no_match /Request information/, ActionMailer::Base.deliveries.first.body
96
+ end
97
+
98
+ def test_body_does_append_request_if_append_is_called
99
+ @advanced.deliver
100
+ assert_match /Request information/, ActionMailer::Base.deliveries.last.body
101
+ end
102
+
103
+ def test_request_title_is_localized
104
+ I18n.backend.store_translations(:en, :simple_form => { :request => { :title => 'Information about the request' } })
105
+ @advanced.deliver
106
+ assert_no_match /Request information/, ActionMailer::Base.deliveries.last.body
107
+ assert_match /Information about the request/, ActionMailer::Base.deliveries.last.body
108
+ end
109
+
110
+ def test_request_info_attributes_are_printed
111
+ @advanced.deliver
112
+ assert_match /Remote ip/, ActionMailer::Base.deliveries.last.body
113
+ assert_match /User agent/, ActionMailer::Base.deliveries.last.body
114
+ end
115
+
116
+ def test_request_info_attributes_are_localized
117
+ I18n.backend.store_translations(:en, :simple_form => { :request => { :remote_ip => 'IP Address' } })
118
+ @advanced.deliver
119
+ assert_match /IP Address/, ActionMailer::Base.deliveries.last.body
120
+ assert_no_match /Remote ip/, ActionMailer::Base.deliveries.last.body
121
+ end
122
+
123
+ def test_request_info_values_are_printed
124
+ @advanced.deliver
125
+ assert_match /0\.0\.0\.0/, ActionMailer::Base.deliveries.last.body
126
+ assert_match /Rails Testing/, ActionMailer::Base.deliveries.last.body
127
+ end
128
+
129
+ def test_request_info_hashes_are_print_inside_lis
130
+ @request.session = { :my => :session, :user => :data }
131
+ @advanced.deliver
132
+ assert_match /<li>my: session<\/li>/, ActionMailer::Base.deliveries.last.body
133
+ assert_match /<li>user: data<\/li>/, ActionMailer::Base.deliveries.last.body
134
+ end
135
+
136
+ def test_error_is_raised_when_append_is_given_but_no_request_is_given
137
+ assert_raise ScriptError do
138
+ @advanced.request = nil
139
+ @advanced.deliver
140
+ end
141
+ end
142
+
143
+ def test_form_with_file_includes_an_attachment
144
+ @with_file.deliver
145
+
146
+ #For some reason I need to encode the mail before the attachments array returns values
147
+ ActionMailer::Base.deliveries.first.to_s
148
+ assert_equal 1, ActionMailer::Base.deliveries.first.attachments.size
149
+ end
150
+
151
+ def test_form_with_file_does_not_output_attachment_as_attribute
152
+ @with_file.deliver
153
+ assert_no_match /File/, ActionMailer::Base.deliveries.first.body
154
+ end
155
+
86
156
  def teardown
87
157
  I18n.reload!
88
158
  end
data/test/test_helper.rb CHANGED
@@ -6,6 +6,7 @@ RAILS_ENV = ENV["RAILS_ENV"] = "test"
6
6
  require 'active_support'
7
7
  require 'active_support/test_case'
8
8
  require 'action_mailer'
9
+ require 'action_controller/test_case'
9
10
 
10
11
  ActionMailer::Base.delivery_method = :test
11
12
 
@@ -22,12 +23,25 @@ class ContactForm < SimpleForm
22
23
  end
23
24
 
24
25
  class AdvancedForm < ContactForm
26
+ append :remote_ip, :user_agent, :session
27
+
25
28
  recipients [ 'my.first@email.com', 'my.second@email.com' ]
26
29
  subject 'My Advanced Form'
27
30
  sender{|c| %{"#{c.name}" <#{c.email}>} }
28
31
  headers 'return-path' => 'mypath'
29
32
  end
30
33
 
34
+ class FileForm < ContactForm
35
+ attribute :file, :attachment => true, :validate => true
36
+ end
37
+
31
38
  class NullRecipient < SimpleForm
32
39
  sender 'my.email@my.domain.com'
33
40
  end
41
+
42
+ #Needed to correctly test an uploaded file
43
+ class ActionController::TestUploadedFile
44
+ def read
45
+ @tempfile.read
46
+ end
47
+ end
@@ -1,4 +1,4 @@
1
- <p><%=h @subject %></p>
1
+ <h4 style="text-decoration:underline"><%=h @subject %></h4>
2
2
 
3
3
  <% @form.class.form_attributes.each do |attribute|
4
4
  value = @form.send(attribute)
@@ -7,3 +7,24 @@
7
7
  <p><b><%= @form.class.human_attribute_name(attribute) %>:</b>
8
8
  <%= value.include?("\n") ? simple_format(h(value)) : h(value) %></p>
9
9
  <% end %>
10
+
11
+ <% unless @form.class.form_appendable.blank? %>
12
+ <br /><h4 style="text-decoration:underline"><%= I18n.t :title, :scope => [ :simple_form, :request ], :default => 'Request information' %></h4>
13
+
14
+ <% @form.class.form_appendable.each do |attribute|
15
+ value = @form.request.send(attribute)
16
+
17
+ value = if value.is_a?(Hash) && !value.empty?
18
+ content_tag(:ul, value.to_a.map{|k,v| content_tag(:li, h("#{k}: #{v.inspect}")) }.join("\n"), :style => "list-style:none;")
19
+ elsif value.is_a?(String)
20
+ h(value)
21
+ else
22
+ h(value.inspect)
23
+ end
24
+ %>
25
+
26
+ <p><b><%= I18n.t attribute, :scope => [ :simple_form, :request ], :default => attribute.to_s.humanize %>:</b>
27
+ <%= value.include?("\n") ? simple_format(value) : value %></p>
28
+ <% end %>
29
+ <br />
30
+ <% end %>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: josevalim-simple_form
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - "Jos\xC3\xA9 Valim"