mailboxer 0.7.0 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +90 -77
- data/app/models/conversation.rb +2 -2
- data/app/models/message.rb +2 -2
- data/app/models/notification.rb +5 -5
- data/app/models/receipt.rb +7 -7
- data/db/migrate/20111204163911_add_attachments.rb +5 -1
- data/db/migrate/20120813110712_rename_receipts_read.rb +9 -0
- data/lib/mailboxer/models/messageable.rb +5 -5
- data/mailboxer.gemspec +7 -6
- data/spec/dummy/db/migrate/20120813110712_rename_receipts_read.rb +9 -0
- data/spec/dummy/db/schema.rb +1 -1
- data/spec/integration/message_and_receipt_spec.rb +26 -26
- data/spec/models/mailboxer_models_messageable_spec.rb +56 -56
- data/spec/models/notification_spec.rb +19 -1
- data/spec/models/receipt_spec.rb +4 -4
- metadata +125 -145
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Mailboxer 0.
|
1
|
+
# Mailboxer 0.8.x [![](https://secure.travis-ci.org/ging/mailboxer.png)](http://travis-ci.org/ging/mailboxer) [![](https://gemnasium.com/ging/mailboxer.png)](https://gemnasium.com/ging/mailboxer)
|
2
2
|
|
3
3
|
This project is based on the need of a private message system for [ging
|
4
4
|
/ social\_stream](https://github.com/ging/social_stream). Instead of creating our core message system heavily
|
@@ -34,27 +34,27 @@ Installation
|
|
34
34
|
|
35
35
|
Add to your Gemfile:
|
36
36
|
|
37
|
-
|
38
|
-
gem
|
39
|
-
|
37
|
+
```ruby
|
38
|
+
gem 'mailboxer'
|
39
|
+
```
|
40
40
|
|
41
41
|
Then run:
|
42
42
|
|
43
|
-
|
43
|
+
```sh
|
44
44
|
$ bundle update
|
45
|
-
|
45
|
+
```
|
46
46
|
|
47
47
|
Run install script:
|
48
48
|
|
49
|
-
|
49
|
+
```sh
|
50
50
|
$ rails g mailboxer:install
|
51
|
-
|
51
|
+
```
|
52
52
|
|
53
53
|
And don't forget to migrate you database:
|
54
54
|
|
55
|
-
|
55
|
+
```sh
|
56
56
|
$ rake db:migrate
|
57
|
-
|
57
|
+
```
|
58
58
|
|
59
59
|
## Requirements & Settings
|
60
60
|
|
@@ -62,7 +62,7 @@ $ rake db:migrate
|
|
62
62
|
|
63
63
|
We are now adding support for sending emails when a Notification or a Message is sent to one o more recipients. You should modify mailboxer initializer (/config/initializer/mailboxer.rb) to edit this settings.
|
64
64
|
|
65
|
-
|
65
|
+
```ruby
|
66
66
|
Mailboxer.setup do |config|
|
67
67
|
#Configures if you applications uses or no the email sending for Notifications and Messages
|
68
68
|
config.uses_emails = true
|
@@ -70,30 +70,30 @@ Mailboxer.setup do |config|
|
|
70
70
|
config.default_from = "no-reply@dit.upm.es"
|
71
71
|
...
|
72
72
|
end
|
73
|
-
|
73
|
+
```
|
74
74
|
|
75
75
|
You can change the way in which emails are delivered by specifying a custom implementation for notification and message mailer
|
76
76
|
|
77
|
-
|
77
|
+
```ruby
|
78
78
|
Mailboxer.setup do |config|
|
79
79
|
config.notification_mailer = CustomNotificationMailer
|
80
80
|
config.message_mailer = CustomMessageMailer
|
81
81
|
...
|
82
82
|
end
|
83
|
-
|
83
|
+
```
|
84
84
|
|
85
85
|
### User identities
|
86
86
|
|
87
87
|
Users must have an identity defined by a `name` and an `email`. We must assure that Messageable models have some specific methods. These methods are:
|
88
88
|
|
89
|
-
|
89
|
+
```ruby
|
90
90
|
#Returning any kind of identification you want for the model
|
91
91
|
def name
|
92
92
|
return "You should add method :name in your Messageable model"
|
93
93
|
end
|
94
|
-
|
94
|
+
```
|
95
95
|
|
96
|
-
|
96
|
+
```ruby
|
97
97
|
#Returning the email address of the model if an email should be sent for this object (Message or Notification).
|
98
98
|
#If no mail has to be sent, return nil.
|
99
99
|
def mailboxer_email(object)
|
@@ -103,11 +103,11 @@ def mailboxer_email(object)
|
|
103
103
|
#if false
|
104
104
|
#return nil
|
105
105
|
end
|
106
|
-
|
106
|
+
```
|
107
107
|
|
108
108
|
These names are explicit enough to avoid colliding with other methods, but as long as you need to change them you can do it by using mailboxer initializer (/config/initializer/mailboxer.rb). Just add or uncomment the following lines:
|
109
109
|
|
110
|
-
|
110
|
+
```ruby
|
111
111
|
Mailboxer.setup do |config|
|
112
112
|
# ...
|
113
113
|
#Configures the methods needed by mailboxer
|
@@ -115,14 +115,14 @@ Mailboxer.setup do |config|
|
|
115
115
|
config.name_method = :name
|
116
116
|
# ...
|
117
117
|
end
|
118
|
-
|
118
|
+
```
|
119
119
|
|
120
120
|
You may change whatever you want or need. For example:
|
121
121
|
|
122
|
-
|
122
|
+
```ruby
|
123
123
|
config.email_method = :notifications_email
|
124
124
|
config.name_method = :display_name
|
125
|
-
|
125
|
+
```
|
126
126
|
|
127
127
|
Will use the method `notification_email(object)` instead of `mailboxer_email(object)` and `display_name` for `name`.
|
128
128
|
|
@@ -132,80 +132,90 @@ Using default or custom method names, if your model doesn't implement them, Mail
|
|
132
132
|
|
133
133
|
In your model:
|
134
134
|
|
135
|
-
|
135
|
+
```ruby
|
136
136
|
class User < ActiveRecord::Base
|
137
137
|
acts_as_messageable
|
138
138
|
end
|
139
|
-
|
139
|
+
```
|
140
140
|
|
141
141
|
You are not limited to User model. You can use Mailboxer in any other model and use it in serveral different models. If you have ducks and cylons in your application and you want to interchange messages as if they where the same, just use act_as_messageable in each one and you will be able to send duck-duck, duck-cylon, cylon-duck and cylon-cylon messages. Of course, you can extend it for as many clases as you need.
|
142
142
|
|
143
143
|
Example:
|
144
144
|
|
145
|
-
|
145
|
+
```ruby
|
146
146
|
class Duck < ActiveRecord::Base
|
147
147
|
acts_as_messageable
|
148
148
|
end
|
149
|
-
|
149
|
+
```
|
150
150
|
|
151
|
-
|
151
|
+
```ruby
|
152
152
|
class Cylon < ActiveRecord::Base
|
153
153
|
acts_as_messageable
|
154
154
|
end
|
155
|
-
|
155
|
+
```
|
156
156
|
|
157
157
|
## Mailboxer API
|
158
158
|
|
159
|
+
### Warning for version 0.8.0
|
160
|
+
Version 0.8.0 sees `Messageable#read` and `Messageable#unread` renamed to `mark_as_(un)read`, and `Receipt#read` and `Receipt#unread` to `is_(un)read`. This may break existing applications, but `read` is a reserved name for Active Record, and the best pratice in this case is simply avoid using it.
|
161
|
+
|
159
162
|
### How can I send a message?
|
160
163
|
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
164
|
+
```ruby
|
165
|
+
#alfa wants to send a message to beta
|
166
|
+
alfa.send_message(beta, "Body", "subject")
|
167
|
+
```
|
165
168
|
|
166
169
|
### How can I reply a message?
|
167
170
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
171
|
+
```ruby
|
172
|
+
#alfa wants to reply to all in a conversation
|
173
|
+
#using a receipt
|
174
|
+
alfa.reply_to_all(receipt, "Reply body")
|
175
|
+
|
176
|
+
#using a conversation
|
177
|
+
alfa.reply_to_conversation(conversation, "Reply body")
|
178
|
+
```
|
175
179
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
180
|
+
```ruby
|
181
|
+
#alfa wants to reply to the sender of a message (and ONLY the sender)
|
182
|
+
#using a receipt
|
183
|
+
alfa.reply_to_sender(receipt, "Reply body")
|
184
|
+
```
|
181
185
|
|
182
186
|
### How can I retrieve my conversations?
|
183
187
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
188
|
+
```ruby
|
189
|
+
#alfa wants to retrieve all his conversations
|
190
|
+
alfa.mailbox.conversations
|
191
|
+
|
192
|
+
#A wants to retrieve his inbox
|
193
|
+
alfa.mailbox.inbox
|
194
|
+
|
195
|
+
#A wants to retrieve his sent conversations
|
196
|
+
alfa.mailbox.sentbox
|
197
|
+
|
198
|
+
#alfa wants to retrieve his trashed conversations
|
199
|
+
alfa.mailbox.trash
|
200
|
+
```
|
194
201
|
|
195
202
|
### How can I paginate conversations?
|
196
203
|
|
197
204
|
You can use Kaminari to paginate the conversations as normal. Please, make sure you use the last version as mailboxer uses `select('DISTINCT conversations.*')` which was not respected before Kaminari 0.12.4 according to its changelog. Working corretly on Kaminari 0.13.0.
|
198
205
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
206
|
+
```ruby
|
207
|
+
#Paginating all conversations using :page parameter and 9 per page
|
208
|
+
conversations = alfa.mailbox.conversations.page(params[:page]).per(9)
|
209
|
+
|
210
|
+
#Paginating received conversations using :page parameter and 9 per page
|
211
|
+
conversations = alfa.mailbox.inbox.page(params[:page]).per(9)
|
212
|
+
|
213
|
+
#Paginating sent conversations using :page parameter and 9 per page
|
214
|
+
conversations = alfa.mailbox.sentbox.page(params[:page]).per(9)
|
215
|
+
|
216
|
+
#Paginating trashed conversations using :page parameter and 9 per page
|
217
|
+
conversations = alfa.mailbox.trash.page(params[:page]).per(9)
|
218
|
+
```
|
209
219
|
|
210
220
|
### How can I read the messages of a conversation?
|
211
221
|
|
@@ -213,19 +223,21 @@ As a messageable, what you receive receipts wich are linked with the message its
|
|
213
223
|
|
214
224
|
This is done this way because receipts save the information about the relation between messageable and the messages: is it read?, is it trashed?, etc.
|
215
225
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
226
|
+
```ruby
|
227
|
+
#alfa gets the last conversation (chronologically, the first in the inbox)
|
228
|
+
conversation = alfa.mailbox.inbox.first
|
229
|
+
|
230
|
+
#alfa gets it receipts chronologically ordered.
|
231
|
+
receipts = conversation.receipts_for alfa
|
232
|
+
|
233
|
+
#using the receipts (i.e. in the view)
|
234
|
+
receipts.each do |receipt|
|
235
|
+
...
|
236
|
+
message = receipt.message
|
237
|
+
read = receipt.is_unread? #or message.is_unread?(alfa)
|
238
|
+
...
|
239
|
+
end
|
240
|
+
```
|
229
241
|
|
230
242
|
You can take a look at the full documentation of Mailboxer in [rubydoc.info](http://rubydoc.info/gems/mailboxer/frames).
|
231
243
|
|
@@ -249,3 +261,4 @@ If you need a GUI you should take a look a this links:
|
|
249
261
|
* [plentz](https://github.com/ging/mailboxer/commits/master?author=plentz) (Diego Plentz)
|
250
262
|
* [laserlemon](https://github.com/ging/mailboxer/commits/master?author=laserlemon) (Steve Richert)
|
251
263
|
* [daveworth](https://github.com/ging/mailboxer/commits/master?author=daveworth) (Dave Worth)
|
264
|
+
* [rafaelgg](https://github.com/ging/mailboxer/commits/master?author=rafaelgg) (Rafael Garcia)
|
data/app/models/conversation.rb
CHANGED
@@ -24,7 +24,7 @@ class Conversation < ActiveRecord::Base
|
|
24
24
|
participant(participant).merge(Receipt.trash)
|
25
25
|
}
|
26
26
|
scope :unread, lambda {|participant|
|
27
|
-
participant(participant).merge(Receipt.
|
27
|
+
participant(participant).merge(Receipt.is_unread)
|
28
28
|
}
|
29
29
|
|
30
30
|
#Mark the conversation as read for one of the participants
|
@@ -125,7 +125,7 @@ class Conversation < ActiveRecord::Base
|
|
125
125
|
#Returns true if the participant has at least one unread message of the conversation
|
126
126
|
def is_unread?(participant)
|
127
127
|
return false if participant.nil?
|
128
|
-
return self.receipts_for(participant).not_trash.
|
128
|
+
return self.receipts_for(participant).not_trash.is_unread.count!=0
|
129
129
|
end
|
130
130
|
|
131
131
|
protected
|
data/app/models/message.rb
CHANGED
@@ -30,7 +30,7 @@ class Message < Notification
|
|
30
30
|
self.recipients.each do |r|
|
31
31
|
msg_receipt = Receipt.new
|
32
32
|
msg_receipt.notification = self
|
33
|
-
msg_receipt.
|
33
|
+
msg_receipt.is_read = false
|
34
34
|
msg_receipt.receiver = r
|
35
35
|
msg_receipt.mailbox_type = "inbox"
|
36
36
|
temp_receipts << msg_receipt
|
@@ -38,7 +38,7 @@ class Message < Notification
|
|
38
38
|
#Sender receipt
|
39
39
|
sender_receipt = Receipt.new
|
40
40
|
sender_receipt.notification = self
|
41
|
-
sender_receipt.
|
41
|
+
sender_receipt.is_read = true
|
42
42
|
sender_receipt.receiver = self.sender
|
43
43
|
sender_receipt.mailbox_type = "sentbox"
|
44
44
|
temp_receipts << sender_receipt
|
data/app/models/notification.rb
CHANGED
@@ -17,7 +17,7 @@ class Notification < ActiveRecord::Base
|
|
17
17
|
joins(:receipts).where('receipts.trashed' => false)
|
18
18
|
}
|
19
19
|
scope :unread, lambda {
|
20
|
-
joins(:receipts).where('receipts.
|
20
|
+
joins(:receipts).where('receipts.is_read' => false)
|
21
21
|
}
|
22
22
|
|
23
23
|
include Concerns::ConfigurableMailer
|
@@ -26,8 +26,8 @@ class Notification < ActiveRecord::Base
|
|
26
26
|
#Sends a Notification to all the recipients
|
27
27
|
def notify_all(recipients,subject,body,obj = nil,sanitize_text = true,notification_code=nil)
|
28
28
|
notification = Notification.new({:body => body, :subject => subject})
|
29
|
-
notification.recipients = recipients.
|
30
|
-
notification.recipients = notification.recipients.uniq
|
29
|
+
notification.recipients = recipients.respond_to?(:each) ? recipients : [recipients]
|
30
|
+
notification.recipients = notification.recipients.uniq if recipients.respond_to?(:uniq)
|
31
31
|
notification.notified_object = obj if obj.present?
|
32
32
|
notification.notification_code = notification_code if notification_code.present?
|
33
33
|
return notification.deliver sanitize_text
|
@@ -58,7 +58,7 @@ class Notification < ActiveRecord::Base
|
|
58
58
|
self.recipients.each do |r|
|
59
59
|
msg_receipt = Receipt.new
|
60
60
|
msg_receipt.notification = self
|
61
|
-
msg_receipt.
|
61
|
+
msg_receipt.is_read = false
|
62
62
|
msg_receipt.receiver = r
|
63
63
|
temp_receipts << msg_receipt
|
64
64
|
end
|
@@ -105,7 +105,7 @@ class Notification < ActiveRecord::Base
|
|
105
105
|
#Returns if the participant have read the Notification
|
106
106
|
def is_unread?(participant)
|
107
107
|
return false if participant.nil?
|
108
|
-
return !self.receipt_for(participant).first.
|
108
|
+
return !self.receipt_for(participant).first.is_read
|
109
109
|
end
|
110
110
|
|
111
111
|
def is_read?(participant)
|
data/app/models/receipt.rb
CHANGED
@@ -22,19 +22,19 @@ class Receipt < ActiveRecord::Base
|
|
22
22
|
scope :inbox, where(:mailbox_type => "inbox")
|
23
23
|
scope :trash, where(:trashed => true)
|
24
24
|
scope :not_trash, where(:trashed => false)
|
25
|
-
scope :
|
26
|
-
scope :
|
25
|
+
scope :is_read, where(:is_read => true)
|
26
|
+
scope :is_unread, where(:is_read => false)
|
27
27
|
|
28
28
|
after_validation :remove_duplicate_errors
|
29
29
|
class << self
|
30
30
|
#Marks all the receipts from the relation as read
|
31
31
|
def mark_as_read(options={})
|
32
|
-
update_receipts({:
|
32
|
+
update_receipts({:is_read => true}, options)
|
33
33
|
end
|
34
34
|
|
35
35
|
#Marks all the receipts from the relation as unread
|
36
36
|
def mark_as_unread(options={})
|
37
|
-
update_receipts({:
|
37
|
+
update_receipts({:is_read => false}, options)
|
38
38
|
end
|
39
39
|
|
40
40
|
#Marks all the receipts from the relation as trashed
|
@@ -78,12 +78,12 @@ class Receipt < ActiveRecord::Base
|
|
78
78
|
|
79
79
|
#Marks the receipt as read
|
80
80
|
def mark_as_read
|
81
|
-
update_attributes(:
|
81
|
+
update_attributes(:is_read => true)
|
82
82
|
end
|
83
83
|
|
84
84
|
#Marks the receipt as unread
|
85
85
|
def mark_as_unread
|
86
|
-
update_attributes(:
|
86
|
+
update_attributes(:is_read => false)
|
87
87
|
end
|
88
88
|
|
89
89
|
#Marks the receipt as trashed
|
@@ -114,7 +114,7 @@ class Receipt < ActiveRecord::Base
|
|
114
114
|
|
115
115
|
#Returns if the participant have read the Notification
|
116
116
|
def is_unread?
|
117
|
-
return !self.
|
117
|
+
return !self.is_read
|
118
118
|
end
|
119
119
|
|
120
120
|
#Returns if the participant have trashed the Notification
|
@@ -96,7 +96,7 @@ module Mailboxer
|
|
96
96
|
#* A Notification
|
97
97
|
#* A Conversation
|
98
98
|
#* An array with any of them
|
99
|
-
def
|
99
|
+
def mark_as_read(obj)
|
100
100
|
case obj
|
101
101
|
when Receipt
|
102
102
|
return obj.mark_as_read if obj.receiver == self
|
@@ -105,9 +105,9 @@ module Mailboxer
|
|
105
105
|
when Conversation
|
106
106
|
obj.mark_as_read(self)
|
107
107
|
when Array
|
108
|
-
obj.map{ |sub_obj|
|
108
|
+
obj.map{ |sub_obj| mark_as_read(sub_obj) }
|
109
109
|
else
|
110
|
-
|
110
|
+
return nil
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
@@ -119,7 +119,7 @@ module Mailboxer
|
|
119
119
|
#* A Notification
|
120
120
|
#* A Conversation
|
121
121
|
#* An array with any of them
|
122
|
-
def
|
122
|
+
def mark_as_unread(obj)
|
123
123
|
case obj
|
124
124
|
when Receipt
|
125
125
|
return obj.mark_as_unread if obj.receiver == self
|
@@ -128,7 +128,7 @@ module Mailboxer
|
|
128
128
|
when Conversation
|
129
129
|
obj.mark_as_unread(self)
|
130
130
|
when Array
|
131
|
-
obj.map{ |sub_obj|
|
131
|
+
obj.map{ |sub_obj| mark_as_unread(sub_obj) }
|
132
132
|
else
|
133
133
|
return nil
|
134
134
|
end
|