has_emails 0.1.4 → 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.rdoc +4 -0
- data/Rakefile +2 -2
- data/lib/has_emails/extensions/action_mailer.rb +100 -102
- data/lib/has_emails.rb +45 -47
- data/test/functional/has_emails_test.rb +3 -3
- data/test/unit/email_address_test.rb +5 -5
- metadata +18 -18
data/CHANGELOG.rdoc
CHANGED
data/Rakefile
CHANGED
@@ -5,7 +5,7 @@ require 'rake/contrib/sshpublisher'
|
|
5
5
|
|
6
6
|
spec = Gem::Specification.new do |s|
|
7
7
|
s.name = 'has_emails'
|
8
|
-
s.version = '0.
|
8
|
+
s.version = '0.2.0'
|
9
9
|
s.platform = Gem::Platform::RUBY
|
10
10
|
s.summary = 'Demonstrates a reference implementation for sending emails with logging and asynchronous support.'
|
11
11
|
|
@@ -13,7 +13,7 @@ spec = Gem::Specification.new do |s|
|
|
13
13
|
s.require_path = 'lib'
|
14
14
|
s.has_rdoc = true
|
15
15
|
s.test_files = Dir['test/**/*_test.rb']
|
16
|
-
s.add_dependency 'has_messages', '>= 0.
|
16
|
+
s.add_dependency 'has_messages', '>= 0.3.0'
|
17
17
|
s.add_dependency 'validates_as_email_address', '>= 0.0.2'
|
18
18
|
|
19
19
|
s.author = 'Aaron Pfeifer'
|
@@ -1,119 +1,117 @@
|
|
1
|
-
module
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
cattr_accessor :default_subject_prefix
|
24
|
-
|
25
|
-
# Specify the prefix to use for the subject. This defaults to the
|
26
|
-
# +default_subject_prefix+ specified for ActionMailer::Base.
|
27
|
-
adv_attr_accessor :subject_prefix
|
28
|
-
|
29
|
-
include PluginAWeek::HasEmails::Extensions::ActionMailer::InstanceMethods
|
30
|
-
extend PluginAWeek::HasEmails::Extensions::ActionMailer::ClassMethods
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
module ClassMethods
|
35
|
-
def self.extended(base) #:nodoc:
|
36
|
-
class << base
|
37
|
-
alias_method_chain :method_missing, :has_emails
|
38
|
-
end
|
39
|
-
end
|
1
|
+
module HasEmails
|
2
|
+
module Extensions #:nodoc:
|
3
|
+
# Adds support for queueing emails so that they can be procssed in the
|
4
|
+
# background. Emails are stored in the database using the Email ActiveRecord
|
5
|
+
# model.
|
6
|
+
#
|
7
|
+
# == Queueing mail
|
8
|
+
#
|
9
|
+
# Once a mailer action and template are defined, you can queue your message
|
10
|
+
# for background processing like so:
|
11
|
+
#
|
12
|
+
# Notifier.queue_signup_notification(john_smith) # Queues the email
|
13
|
+
#
|
14
|
+
# If you were to deliver the mail immediately, the normal process would be
|
15
|
+
# used like so:
|
16
|
+
#
|
17
|
+
# Notifier.deliver_signup_notification(john_smith) # Delivers the email
|
18
|
+
module ActionMailer
|
19
|
+
def self.included(base) #:nodoc:
|
20
|
+
base.class_eval do
|
21
|
+
@@default_subject_prefix = "[#{File.basename(File.expand_path(Rails.root)).camelize}] "
|
22
|
+
cattr_accessor :default_subject_prefix
|
40
23
|
|
41
|
-
#
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
24
|
+
# Specify the prefix to use for the subject. This defaults to the
|
25
|
+
# +default_subject_prefix+ specified for ActionMailer::Base.
|
26
|
+
adv_attr_accessor :subject_prefix
|
27
|
+
|
28
|
+
include HasEmails::Extensions::ActionMailer::InstanceMethods
|
29
|
+
extend HasEmails::Extensions::ActionMailer::ClassMethods
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
def self.extended(base) #:nodoc:
|
35
|
+
class << base
|
36
|
+
alias_method_chain :method_missing, :has_emails
|
51
37
|
end
|
52
38
|
end
|
53
39
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# Sets or gets the subject of the email. All subjects are prefixed with a
|
64
|
-
# value indicating the application it is coming from.
|
65
|
-
def subject_with_prefix(*parameters)
|
66
|
-
if parameters.empty?
|
67
|
-
subject_without_prefix
|
40
|
+
# Handles calls to queue_*
|
41
|
+
def method_missing_with_has_emails(method_symbol, *parameters)
|
42
|
+
case method_symbol.id2name
|
43
|
+
when /^queue_([_a-z]\w*)/
|
44
|
+
# Queues the mail so that it's processed in the background
|
45
|
+
new($1, *parameters).queue
|
68
46
|
else
|
69
|
-
|
70
|
-
|
47
|
+
# Handle the mail delivery as normal
|
48
|
+
method_missing_without_has_emails(method_symbol, *parameters)
|
71
49
|
end
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module InstanceMethods
|
54
|
+
def self.included(base) #:nodoc:
|
55
|
+
base.class_eval do
|
56
|
+
alias_method_chain :initialize_defaults, :subject_prefix
|
57
|
+
alias_method_chain :subject, :prefix
|
58
|
+
alias_method :subject=, :subject_with_prefix
|
77
59
|
end
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
@sent_on = email.updated_at
|
60
|
+
end
|
61
|
+
|
62
|
+
# Sets or gets the subject of the email. All subjects are prefixed with a
|
63
|
+
# value indicating the application it is coming from.
|
64
|
+
def subject_with_prefix(*parameters)
|
65
|
+
if parameters.empty?
|
66
|
+
subject_without_prefix
|
67
|
+
else
|
68
|
+
subject_without_prefix(subject_prefix + subject_without_prefix(*parameters))
|
88
69
|
end
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
70
|
+
end
|
71
|
+
|
72
|
+
# Sets the default subject prefix
|
73
|
+
def initialize_defaults_with_subject_prefix(method_name) #:nodoc
|
74
|
+
initialize_defaults_without_subject_prefix(method_name)
|
75
|
+
@subject_prefix ||= ::ActionMailer::Base.default_subject_prefix.dup
|
76
|
+
end
|
77
|
+
|
78
|
+
# Delivers an email based on the content in the specified email
|
79
|
+
def email(email)
|
80
|
+
@from = email.sender.with_name
|
81
|
+
@recipients = email.to.map(&:with_name)
|
82
|
+
@cc = email.cc.map(&:with_name)
|
83
|
+
@bcc = email.bcc.map(&:with_name)
|
84
|
+
@subject = email.subject || ''
|
85
|
+
@body = email.body || ''
|
86
|
+
@sent_on = email.updated_at
|
87
|
+
end
|
88
|
+
|
89
|
+
# Queues the current e-mail that has been constructed
|
90
|
+
def queue
|
91
|
+
Email.transaction do
|
92
|
+
# Create the main email
|
93
|
+
email = EmailAddress.find_or_create_by_address(from).emails.build(
|
94
|
+
:subject => subject,
|
95
|
+
:body => body,
|
96
|
+
:to => email_addresses_for(:recipients),
|
97
|
+
:cc => email_addresses_for(:cc),
|
98
|
+
:bcc => email_addresses_for(:bcc)
|
99
|
+
)
|
100
|
+
email.queue!
|
103
101
|
end
|
104
|
-
|
105
|
-
private
|
106
|
-
# Finds or creates all of the email addresses for the given type of
|
107
|
-
# recipient (can be :recipients, :cc, or :bcc)
|
108
|
-
def email_addresses_for(kind)
|
109
|
-
[send(kind)].flatten.collect {|address| EmailAddress.find_or_create_by_address(address)}
|
110
|
-
end
|
111
102
|
end
|
103
|
+
|
104
|
+
private
|
105
|
+
# Finds or creates all of the email addresses for the given type of
|
106
|
+
# recipient (can be :recipients, :cc, or :bcc)
|
107
|
+
def email_addresses_for(kind)
|
108
|
+
[send(kind)].flatten.collect {|address| EmailAddress.find_or_create_by_address(address)}
|
109
|
+
end
|
112
110
|
end
|
113
111
|
end
|
114
112
|
end
|
115
113
|
end
|
116
114
|
|
117
115
|
ActionMailer::Base.class_eval do
|
118
|
-
include
|
116
|
+
include HasEmails::Extensions::ActionMailer
|
119
117
|
end
|
data/lib/has_emails.rb
CHANGED
@@ -2,58 +2,56 @@ require 'has_messages'
|
|
2
2
|
require 'validates_as_email_address'
|
3
3
|
require 'has_emails/extensions/action_mailer'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
module
|
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
|
-
|
5
|
+
# Adds a generic implementation for sending emails
|
6
|
+
module HasEmails
|
7
|
+
module MacroMethods
|
8
|
+
# Creates the following email associations:
|
9
|
+
# * +emails+ - Emails that were composed and are visible to the owner. Emails may have been sent or unsent.
|
10
|
+
# * +received_emails - Emails that have been received from others and are visible. Emails may have been read or unread.
|
11
|
+
#
|
12
|
+
# == Creating new emails
|
13
|
+
#
|
14
|
+
# To create a new email, the +emails+ association should be used, for example:
|
15
|
+
#
|
16
|
+
# address = EmailAddress.find(123)
|
17
|
+
# email = user.emails.build
|
18
|
+
# email.subject = 'Hello'
|
19
|
+
# email.body = 'How are you?'
|
20
|
+
# email.to EmailAddress.find(456)
|
21
|
+
# email.save!
|
22
|
+
# email.deliver!
|
23
|
+
def has_emails
|
24
|
+
has_many :emails,
|
25
|
+
:as => :sender,
|
26
|
+
:class_name => 'Email',
|
27
|
+
:conditions => {:hidden_at => nil},
|
28
|
+
:order => 'messages.created_at ASC'
|
29
|
+
has_many :received_emails,
|
30
|
+
:as => :receiver,
|
31
|
+
:class_name => 'MessageRecipient',
|
32
|
+
:include => :message,
|
33
|
+
:conditions => ['message_recipients.hidden_at IS NULL AND messages.state = ?', 'sent'],
|
34
|
+
:order => 'messages.created_at ASC'
|
35
|
+
|
36
|
+
include HasEmails::InstanceMethods
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module InstanceMethods
|
41
|
+
# Composed emails that have not yet been sent. These consists of all
|
42
|
+
# emails that are currently in the "unsent" state.
|
43
|
+
def unsent_emails
|
44
|
+
emails.with_state('unsent')
|
39
45
|
end
|
40
46
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
emails.with_state('unsent')
|
46
|
-
end
|
47
|
-
|
48
|
-
# Composed emails that have already been sent. These consist of all emails
|
49
|
-
# that are currently in the "queued" or "sent states.
|
50
|
-
def sent_emails
|
51
|
-
emails.with_states(%w(queued sent))
|
52
|
-
end
|
47
|
+
# Composed emails that have already been sent. These consist of all emails
|
48
|
+
# that are currently in the "queued" or "sent states.
|
49
|
+
def sent_emails
|
50
|
+
emails.with_states(%w(queued sent))
|
53
51
|
end
|
54
52
|
end
|
55
53
|
end
|
56
54
|
|
57
55
|
ActiveRecord::Base.class_eval do
|
58
|
-
extend
|
56
|
+
extend HasEmails::MacroMethods
|
59
57
|
end
|
@@ -105,18 +105,18 @@ class EmailAddressWithHiddenEmailsTest < Test::Unit::TestCase
|
|
105
105
|
@friend = create_email_address(:spec => 'jane.smith@gmail.com')
|
106
106
|
|
107
107
|
hidden_unsent_email = create_email(:sender => @email_address)
|
108
|
-
hidden_unsent_email.hide
|
108
|
+
hidden_unsent_email.hide
|
109
109
|
@unsent_email = create_email(:sender => @email_address)
|
110
110
|
|
111
111
|
hidden_sent_email = create_email(:sender => @email_address, :to => @friend)
|
112
112
|
hidden_sent_email.deliver
|
113
|
-
hidden_sent_email.hide
|
113
|
+
hidden_sent_email.hide
|
114
114
|
@sent_email = create_email(:sender => @email_address, :to => @friend)
|
115
115
|
@sent_email.deliver
|
116
116
|
|
117
117
|
hidden_received_email = create_email(:sender => @friend, :to => @email_address)
|
118
118
|
hidden_received_email.deliver
|
119
|
-
hidden_received_email.recipients.first.hide
|
119
|
+
hidden_received_email.recipients.first.hide
|
120
120
|
@received_email = create_email(:sender => @friend, :to => @email_address)
|
121
121
|
@received_email.deliver
|
122
122
|
end
|
@@ -23,19 +23,19 @@ class EmailAddressTest < Test::Unit::TestCase
|
|
23
23
|
def test_should_require_a_spec
|
24
24
|
email_address = new_email_address(:spec => nil)
|
25
25
|
assert !email_address.valid?
|
26
|
-
|
26
|
+
assert email_address.errors.invalid?(:spec)
|
27
27
|
end
|
28
28
|
|
29
29
|
def test_should_require_a_properly_formatted_email
|
30
30
|
email_address = new_email_address(:spec => '!@@!@@!')
|
31
31
|
assert !email_address.valid?
|
32
|
-
|
32
|
+
assert email_address.errors.invalid?(:spec)
|
33
33
|
end
|
34
34
|
|
35
35
|
def test_should_not_allow_emails_less_than_3_characters
|
36
36
|
email_address = new_email_address(:spec => 'aa')
|
37
37
|
assert !email_address.valid?
|
38
|
-
|
38
|
+
assert email_address.errors.invalid?(:spec)
|
39
39
|
|
40
40
|
email_address.spec = 'a@a'
|
41
41
|
assert email_address.valid?
|
@@ -47,7 +47,7 @@ class EmailAddressTest < Test::Unit::TestCase
|
|
47
47
|
|
48
48
|
email_address.spec += 'a'
|
49
49
|
assert !email_address.valid?
|
50
|
-
|
50
|
+
assert email_address.errors.invalid?(:spec)
|
51
51
|
end
|
52
52
|
|
53
53
|
def test_should_require_a_unique_spec_scoped_by_name
|
@@ -58,7 +58,7 @@ class EmailAddressTest < Test::Unit::TestCase
|
|
58
58
|
|
59
59
|
second_email_address = new_email_address(:spec => 'john.smith@gmail.com', :name => 'John Smith')
|
60
60
|
assert !second_email_address.valid?
|
61
|
-
|
61
|
+
assert second_email_address.errors.invalid?(:spec)
|
62
62
|
end
|
63
63
|
|
64
64
|
def test_should_not_require_a_name
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_emails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Pfeifer
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-12-14 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,7 +20,7 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 0.
|
23
|
+
version: 0.3.0
|
24
24
|
version:
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: validates_as_email_address
|
@@ -46,28 +46,28 @@ files:
|
|
46
46
|
- app/models/email_address.rb
|
47
47
|
- db/migrate
|
48
48
|
- db/migrate/001_create_email_addresses.rb
|
49
|
+
- lib/has_emails.rb
|
49
50
|
- lib/has_emails
|
50
51
|
- lib/has_emails/extensions
|
51
52
|
- lib/has_emails/extensions/action_mailer.rb
|
52
|
-
-
|
53
|
-
- test/
|
54
|
-
- test/app_root/app
|
55
|
-
- test/app_root/app/models
|
56
|
-
- test/app_root/app/models/empty
|
57
|
-
- test/app_root/config
|
58
|
-
- test/app_root/config/environment.rb
|
59
|
-
- test/app_root/db
|
60
|
-
- test/app_root/db/migrate
|
61
|
-
- test/app_root/db/migrate/001_migrate_has_messages_to_version_2.rb
|
62
|
-
- test/app_root/db/migrate/002_migrate_has_emails_to_version_1.rb
|
53
|
+
- test/factory.rb
|
54
|
+
- test/test_helper.rb
|
63
55
|
- test/functional
|
64
56
|
- test/functional/has_emails_test.rb
|
65
|
-
- test/test_helper.rb
|
66
|
-
- test/factory.rb
|
67
57
|
- test/unit
|
68
|
-
- test/unit/email_address_test.rb
|
69
58
|
- test/unit/action_mailer_test.rb
|
70
59
|
- test/unit/email_test.rb
|
60
|
+
- test/unit/email_address_test.rb
|
61
|
+
- test/app_root
|
62
|
+
- test/app_root/db
|
63
|
+
- test/app_root/db/migrate
|
64
|
+
- test/app_root/db/migrate/002_migrate_has_emails_to_version_1.rb
|
65
|
+
- test/app_root/db/migrate/001_migrate_has_messages_to_version_2.rb
|
66
|
+
- test/app_root/config
|
67
|
+
- test/app_root/config/environment.rb
|
68
|
+
- test/app_root/app
|
69
|
+
- test/app_root/app/models
|
70
|
+
- test/app_root/app/models/empty
|
71
71
|
- CHANGELOG.rdoc
|
72
72
|
- init.rb
|
73
73
|
- LICENSE
|
@@ -101,6 +101,6 @@ specification_version: 2
|
|
101
101
|
summary: Demonstrates a reference implementation for sending emails with logging and asynchronous support.
|
102
102
|
test_files:
|
103
103
|
- test/functional/has_emails_test.rb
|
104
|
-
- test/unit/email_address_test.rb
|
105
104
|
- test/unit/action_mailer_test.rb
|
106
105
|
- test/unit/email_test.rb
|
106
|
+
- test/unit/email_address_test.rb
|