No commit activity in last 3 years
No release in over 3 years
Parse, store retreive and format hashtags in your text.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

 Project Readme

SimpleHashtag

Gem Version Code Climate

Ruby gem for Rails that parses, stores, retreives and formats hashtags in your model.

Simple Hashtag is a mix between–well–hashtags, as we know them, and categories. It will scan your Active Record attribute for a hashtag, store it in an index, and display a page with each object containing the tag.

It's simple, and like all things simple, it can create a nice effect, quickly.

Installation

Add this line to your application's Gemfile:

gem 'simple_hashtag'

And execute:

$ bundle

Then you have to generate the migration files:

$ rails g simple_hashtag:migration

This will create two migration files, one for the hashtags table and one for the hashtagging table. You will need to run rake db:migrate to actually create the tables.

Optionnally, you can create views, if only to guide you through your own implementation:

$ rails g simple_hashtag:views

This will create a basic controller, a short index view and a small helper. It assume your views follow the convention of having a directory named after your model's plural, and a partial named after your model's name.

app
|-- views
|    |-- posts
|    |    |-- _post.html.erb

Usage

Just add include SimpleHashtag::Hashtaggable in your model.

Simple Hasthag will parse the body attribute by default:

class Post < ActiveRecord::Base
  include SimpleHashtag::Hashtaggable
end

If you need to parse another attribute instead, add hashtaggable_attribute followed by the name of your attribute, i.e.:

class Picture < ActiveRecord::Base
  include SimpleHashtag::Hashtaggable
  hashtaggable_attribute :caption
end

From here on, if your text contains a hashtag, say #RubyRocks, Simple Hasthag will find it, store it in a table and retreive it and its associated object if asked. Helpers are also available to create a link when displaying the text.

Controller and Views

If you don't want to bother looking at the genrerated controller and views, here is a quick peek. In a Controller, display all hashtags, or search for a Hashtag and its associated records:

class HashtagsController < ApplicationController
  def index
    @hashtags = SimpleHashtag::Hashtag.all
  end

  def show
    @hashtag = SimpleHashtag::Hashtag.find_by_name(params[:hashtag])
    @hashtagged = @hashtag.hashtaggables if @hashtag
  end
end

The views could resemble something like this:

Index:

<h1>Hashtags</h1>
<ul>
<% @hashtags.each do |hashtag| %>
  <li><%= link_to hashtag.name, hashtag_path(hashtag.name) %></li>
<% end -%>
</ul>

Show:

<h1><%= params[:hashtag] %></h1>
<% if @hashtagged %>
  <% @hashtagged.each do |hashtagged| %>
    <% view    = hashtagged.class.to_s.underscore.pluralize %>
    <% partial = hashtagged.class.to_s.underscore %>
    <%= render "#{view}/#{partial}", {partial.to_sym => hashtagged} %>
  <% end -%>
<% else -%>
  <p>There is no match for the <em><%= params[:hashtag] %></em> hashtag.</p>
<% end -%>

In the gem it is actually extracted in a helper.

Routes

If you use the provided controller and views, the generator will add two routes to your app:

get 'hashtags/',         to: 'hashtags#index',     as: :hashtags
get 'hashtags/:hashtag', to: 'hashtags#show',      as: :hashtag

The helper generating the link relies on it.

Spring Cleaning

There is a class method SimpleHashtag::Hashtag#clean_orphans to remove unused hashtags from the DB. It is currently not hooked, for two reasons:

  • It is not optimised at all, DB-wise.
  • Destructive method should be called explicitly.

Knowing all this, you can hook it after each change, or automate it with a Cron job, or even spring-clean manually once in a while.

Improvements for this method are listed in the Todo section below.

Gotchas

Association Query

The association between a Hashtag and your models is a polymorphic many-to-many.

The object returned by the query is an array, not an Arel query, so you can't chain (i.e.: to specify the order), and should do it by hand:

hashtag = SimpleHashtag.find_by_name("RubyRocks")
posts_and_picts = hashtag.hattaggables
posts_and_picts.sort_by! { |p| p.created_at }

find_by

To preserve coherence, Hashtags are stored downcased. To ensure coherence, they are also searched downcased. Internally, the model overrides find_by_name to perform the downcase query. Should you search Hashtags manually you should use the SimpleHashtag::Hashtag#find_by_name method, instead of SimpleHashtag::Hashtag.find_by(name: 'RubyRocks')

ToDo

Simple Hashtag is in its very early stage and would need a lot of love to reach 1.0.0. Among the many improvement areas:

  • Make the Regex that parses the text for the hashtag much more robust. This is how Twitter does it: https://github.com/twitter/twitter-text-rb/blob/master/lib/twitter-text/regex.rb (Yes, that's 362 lines of regex. Neat.)
  • Allow for multiple hashtagable attributes on the same model
  • Allow a change in the name of the classes and tables to avoid conflicts
  • Make it ORM agnostic
  • Add an option so the helper displays the # or not, global or per model
  • Add an option to clean orphans after each edit or not
  • Improve the SimpleHashtag::Hashtag#clean_orphans method to do only one SQL query

Contributing

All contributions are welcome. I might not develop new features (unless a project does require it), but I will definitely merge any interesting feature or bug fix quickly.

You know the drill:

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Add passing tests
  4. Commit your changes (git commit -am 'Add some feature')
  5. Push to the branch (git push origin my-new-feature)
  6. Create new Pull Request