MentionSystem
An active record mention system developed using ruby on rails applying domain driven design and test driven development principles.
- For rails 4 support use branch v0.0.7-stable.
- For rails 5 support use branch v0.1.1-stable.
- For rails 6+ support use the latest version.
This gem is heavily influenced by cmer/socialization.
Installation
Add this line to your application's Gemfile:
gem 'mention_system'
And then execute:
$ bundle
Or install it yourself as:
$ gem install mention_system
Usage
Run the generator
$ rails g mention_system
Let's suppose for a moment that you have a blog application and a Post can mention a User or several User models. The post model becomes the mentioner and the user model becomes the mentionee.
User object
class User < ActiveRecord::Base
act_as_mentionee
validates :username, { presence: true, uniqueness: true }
end
Post object
class Post < ActiveRecord::Base
act_as_mentioner
validates :content, presence: true
end
Mentionee object methods
user.is_mentionee? # returns true
user.mentioned_by?(post) # returns true if post mentions the user object, false otherwise
user.mentioners_by(Post) # returns a scope of MentionSystem::Mention join model that belongs to the user object and belongs to mentioner objects of type Post
Mentioner object methods
post.is_mentioner? # returns true
post.mention(user) # Creates an instance of MentionSystem::Mention join model associating the post object and the user object, returns true if succeded, false otherwise
post.unmention(user) # Destroys an instance of MentionSystem::Mention join model that associates the post object and the user object, returns true if succeded, false otherwise
post.toggle_mention(user) # Mentions / unmentions the user
post.mentions?(user) # returns true if the post object mentions the user object, false otherwise
post.mentionees_by(User) # returns a scope of MentionSystem::Mention join model that belongs to the post object and belongs to mentionee objects of type User
Mention processors
Mention processors are objects in charge of computing mentions between mentioner objects and mentionee objects. The framework provides a base mention processor class that the developer should subclass. Mention processors provide after / before callbacks to hook custom behavior before and after a mention is computed.
Let's suppose we want to parse a post content and process mentions in the form of "@username". We first define a custom mention processor instructing how to compute a post content and how to retrieve a collection of users by the handles mentioned in the post content.
CustomMentionProcessor object
class CustomMentionProcessor < MentionSystem::MentionProcessor
###
# This method returns the content used to parse mentions from the mentioner object, in this case is post's content
###
def extract_mentioner_content(post)
post.content
end
###
# This method should return a collection (must respond to each) of mentionee objects for a given set of handles
# In our case will be a collection of user objects
###
def find_mentionees_by_handles(*handles)
User.where(username: handles)
end
end
When we call
user1 = User.create(username: "test1")
user2 = User.create(username: "test2")
post = Post.create(content: "Post content mentioning @test1 and @test2")
m = CustomMentionProcessor.new
m.process_mentions(post)
It will process a mention between "post" and "user1" and also a mention between "post" and "user2".
Mention processor callbacks
Suppose we want to validate if a user can be mentioned before a mention is processed, we can register a before callback in the mention processor. Now lets suppose we want to send a notification email when a mention is given to a user, we can register an after callback in the mention processor.
Lets see an example of both:
m = CustomMentionProcessor.new
m.add_before_callback Proc.new { |post, user| user.mentions_allowed? }
m.add_after_callback Proc.new { |post, user| UserMailer.notify_mention(post, user) }
m.process_mentions(post)
Now when the mention processor process the mentions in the post content, it should validate first if the user is allowed to mention and after the mention is processed an email sent notifying the mention.
You can register several callbacks and they will be called in order.
- When a before callback return false it will not call any further before callback, nor process the mention nor will call any after callbacks.
- When a mention could not be processed none of the after callbacks will be called.
- When an after callback returns false it will not call any further after callback.
You can override the prefix used to parse mentions, it defaults to "@" but you can change to any prefix you like, for example "#", so that mention processors can recognize #test1 and #test2 instead of @user1 and @user2.
To do that you need to override the mention_prefix method in the mention processor.
class CustomMentionProcessor < MentionSystem::MentionProcessor
private:
###
# Defines the mention prefix used to parse mentions, defaults "@"
###
def mention_prefix
"#"
end
end
For more information read the api documentation.
Contributing
- Fork it ( https://github.com/pmviva/mention_system/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create a new Pull Request