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 +2 -0
- data/README +51 -19
- data/lib/simple_form/base.rb +8 -3
- data/lib/simple_form/dsl.rb +28 -3
- data/lib/simple_form/notifier.rb +28 -7
- data/lib/simple_form.rb +9 -7
- data/test/errors_test.rb +4 -2
- data/test/notifier_test.rb +75 -5
- data/test/test_helper.rb +14 -0
- data/views/simple_form/notifier/contact.erb +22 -1
- metadata +1 -1
data/CHANGELOG
CHANGED
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,
|
21
|
-
attribute :email,
|
22
|
-
attribute :
|
23
|
-
|
24
|
-
attribute :message
|
25
|
-
attribute :nickname,
|
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
|
36
|
-
|
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(
|
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:
|
149
|
+
contact_form: "Your site contact form"
|
125
150
|
attributes:
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
telephone: Telefone
|
130
|
-
message: Mensagem
|
151
|
+
email: "E-mail"
|
152
|
+
telephone: "Telephone number"
|
153
|
+
message: "Sent message"
|
131
154
|
messages:
|
132
|
-
blank: "
|
133
|
-
invalid: "
|
134
|
-
telephone: "
|
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
|
-----------------
|
data/lib/simple_form/base.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/simple_form/dsl.rb
CHANGED
@@ -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[:
|
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(
|
100
|
-
|
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
|
data/lib/simple_form/notifier.rb
CHANGED
@@ -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
|
-
|
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
|
-
#
|
18
|
+
# Initialize arrays and hashes
|
19
19
|
#
|
20
|
-
|
21
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
data/test/notifier_test.rb
CHANGED
@@ -3,8 +3,15 @@ require File.dirname(__FILE__) + '/test_helper'
|
|
3
3
|
class SimpleFormNotifierTest < ActiveSupport::TestCase
|
4
4
|
|
5
5
|
def setup
|
6
|
-
@form
|
7
|
-
|
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.
|
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 => { :
|
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
|
-
<
|
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 %>
|