Reputation: 873
I am implementing a notification system for my application. I have many type of notifications, each of them has different number of references to other users. For example, Progress Updated notification has no references to any other user, while Agency Added Patient notification has 2 references, 1 to an admin and other one to a patient.
I've implemented all these types as a different ActiveRecord object, and created a model for each one. Each of them acts_as a Notification, where Notification is actable (see active_record-acts_as gem. Each different type of notification has its own table, and its own very specific columns. Since they are about different events, they have their own texts.
Initially, I hard coded this texts into the model methods, like this:
class Notification < ActiveRecord::Base
actable
end
class NotificationTypeA < ActiveRecord::Base
acts_as :notification
def notify
"This is notification A."
end
end
class NotificationTypeB < ActiveRecord::Base
acts_as :notification
def notify
user = User.find(self.notification_user_id)
"This is notification B about the user #{user.name}"
end
end
And render the notifications like this:
// _header.html.erb
<% current_user.notifications.where(:is_read => false).order('created_at DESC').each do |n| %>
<li style="padding-top: 15px; padding-right: 6px;">
<%= render :partial => "notifications/notification", :locals => {:n => n} %>
</li>
<% end %>
// notifications/_notification.html.erb
<%= n.specific.notify %>
However, I know it is not a good practice to incorporate view elements to models. Additionally, I can not use Rails Internalization (I18n) methods in models, so I can not translate them. If I go the other way, I can create a new view for each notification type, which they will only differ in their notification texts.
Which one is a better practice for a notification system? Or do you have any suggestions that make this better? I thought this one is a pretty good until I noticed that it is a bad practice and I am unable to use internalization methods in my solution.
Upvotes: 1
Views: 634
Reputation: 230521
First, it's not "internalization", it's "internationalization". Quite a mouthful, that's why it's always called "I18n".
Second, there's an easy solution: return i18n keys (along with dynamic data) from notification objects
def notify
[
'notifications.type_b.text', # or whatever
{ username: User.find(self.notification_user_id).name },
]
end
Then in locale files
notifications:
type_b:
text: "This is notification B about the user %{username}"
Then in the view
// notifications/_notification.html.erb
<%= t(*n.specific.notify) %>
t(*n.specific.notify)
is more or less like this:
notif_data = n.specific.notify
key = notif_data.first # 'notifications.type_b.text'
data = notif_data.last # { username: 'John' }
I18n.t(key, data)
You can use I18n in models
def notify
I18n.t('notifications.type_b.text', username: 'John')
end
Upvotes: 3