Ruby on Rails Get a User’s Gravatar

Ruby on Rails Get a User's Gravatar

Gravatar is a Fantastic service that provides a universal avatar for users. Gravatar has designed their service in such a way that the user’s avatar can be rendered on any site free of charge. Gravatar is used on millions of sites across the globe including GitHub, Stack Overflow, Word Press, Disqus, and many more sites. You can easily use gravatar without much effort. Simply add the code below to your application helper:

1
2
3
4
5
6
module ApplicationHelper
  def gravatar_url(email, size)
    gravatar = Digest::MD5::hexdigest(email).downcase
    url = "http://gravatar.com/avatar/#{gravatar}.png?s=#{size}"
  end
end

The first parameter, email, is the email address you wish to obtain the gravatar for. The second parameter, size, is the size of the gravatar you wish to render. To actually get the link to the gravatar, we obtain an MD5 hash of the email and then lowercase it and append it to the end of the gravatar url. The size is specified using the s parameter. To use this function, simple pass the newly generated Gravatar url to an image tag like this:

1
<%= image_tag gravatar_url("you@youremail.com", 64), alt: "" %>

This will render the gravatar for that email address or a default image if the avatar doesn’t exist. If you wish to specify your default image, you can modify your helper to look like the code listed below, changing the default url to whatever you wish:

1
2
3
4
5
def gravatar_url(email, size)
  gravatar_id = Digest::MD5::hexdigest(email).downcase
  default_url = "http://mysite.com/myavatar.png"
  url = "http://gravatar.com/avatar/#{gravatar_id}.png?s=#{size}&d=#{CGI::escape(default_url)}"
end

This will use whatever default URL you provide for the default url variable.

So far so good, That’s it!!! See ya!!! :)

Put Ruby on Rails on a Slim

Put Ruby on Rails on a Slim

Ruby on Rails is my usual framework of choice to build web applications. It is good and easy to use, but let’s face it: it’s massive compared to more lightweight frameworks, such as Sinatra. Why is it bad? There are a few reasons and slow start-up time and high resources usage are just two most common concerns. Slimming down Ruby on Rails applications can allow you to use different components (say Sequel instead of ActiveRecord) and improve system security. Remember the last year’s security dramas related to JSON parameters parsing? It would be largely irrelevant for most applications if everyone who does not use it, disabled it.

Rails Modularity
To enable individual modules, replace the following in config/application.rb:

config/application.rb
1
require 'rails/all'

With:

config/application.rb
1
2
3
4
5
require 'active_record/railtie'
require 'action_controller/railtie'
require 'action_mailer/railtie'
require 'active_model/railtie'
require 'sprockets/railtie'

As you can see above, you can remove ActiveRecord altogether if you use different database, the same with ActionMailer or Sprockets. It probably does not make sense to remove ActionController, however.

Internal Middleware Stack
Each Ruby on Rails applications comes with Internal Middleware Stack Enabled. Check out This Section of Documentation for a list and description of each component. On a fairly small Ruby on Rails application I work on, the stack looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ rake middleware
use Rack::Sendfile
use ActionDispatch::Static
use #<ActiveSupport::Cache::Strategy::LocalCache::Middleware:0x007f0bda2d73e0>
use Rack::Runtime
use Rack::MethodOverride
use ActionDispatch::RequestId
use Rails::Rack::Logger
use ActionDispatch::ShowExceptions
use ActionDispatch::DebugExceptions
use ActionDispatch::RemoteIp
use ActionDispatch::Callbacks
use ActionDispatch::Cookies
use ActionDispatch::Session::CookieStore
use ActionDispatch::Flash
use ActionDispatch::ParamsParser
use Rack::Head
use Rack::ConditionalGet
use Rack::ETag
run Blog::Application.routes

I can safely disable most of the above by modifying config/application.rb, for example:

config/application.rb
1
config.middleware.disable "Rack::ETag"

The same way, I was able to disable most of the default middleware, without doing any harm to my little app. You will have to be careful, however, what you disable. If you use login system, you will need sessions, if you display flash messages do not remove “ActionDispatch::Flash”… etc.

When it comes to JSON parameters parsing, that was a headache for most Ruby on Rails developers last year, it can be easily disabled. To disable JSON params parsing, put this line into config/application.rb:

config/application.rb
1
config.middleware.swap ActionDispatch::ParamsParser, ActionDispatch::ParamsParser, Mime::JSON => nil

Rails API
If you are building only API for your application, you can use nice gem called rails-api.

Put Controllers on a Hunger Slim
If you check out Ruby on Rails source code for ActionController::Base, you will learn that it inherits from ActionController::Metal and includes Bunch of Modules that you might or might not need in your controllers. A way to slim down your controllers stack, is to cherry-pick the ones you need. If all you need is basic rendering, there is nothing stopping you from creating lightweight controllers like this one:

1
2
3
4
5
6
7
class SlimController < ActionController::Metal
  include ActionController::Rendering

  def index
    render text: "I'm Slim, yes I'm the real Bunlong"
  end
end

There is no ActionController:HipHop I’m afraid, but that will work just as good.

Single File Rails Applications
Okay, they don’t have to be single-file. But you are not forced to use default Rails catalogues structure, and you can make them really slim and custom.

You can, however, create 100% functional Rails application only in config.ru:

config.ru
1
2
3
4
5
6
7
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# Port of https://gist.github.com/josevalim/1942658 to Rails 4
# Original author: Jose Valim
#
# Run this file with:
#
#   bundle exec RAILS_ENV=production rackup -p 3000 -s thin
#
# And access:
#
#   http://localhost:3000/hello/world
#
# We are using Bundler in this example, but we could also
# have used rubygems:
#
#   require "rubygems"
#
#   gem "actionpack"
#   gem "railties"
#
#   require "rails"
#   require "rails/all"

# The following lines should come as no surprise. Except by
# ActionController::Metal, it follows the same structure of
# config/application.rb, config/environment.rb and config.ru
# existing in any Rails 4 app. Here they are simply in one
# file and without the comments.
require "rails"
require "action_controller/railtie" # require more if needed

class MyApp < Rails::Application
  routes.append do
    get "/hello/world" => "hello#world"
  end

  # Enable cache classes. Production style.
  config.cache_classes = true

  # uncomment below to display errors
  # config.consider_all_requests_local = true

  # Here you could remove some middlewares, for example
  # Rack::Lock, ActionDispatch::Flash and  ActionDispatch::BestStandardsSupport below.
  # The remaining stack is printed on rackup (for fun!).
  # Rails API has config.middleware.api_only! to get
  # rid of browser related middleware.
  config.middleware.delete "Rack::Lock"
  config.middleware.delete "ActionDispatch::Flash"
  config.middleware.delete "ActionDispatch::BestStandardsSupport"

  # We need a secret token for session, cookies, etc.
  config.secret_token = "49837489qkuweoiuoqwehisuakshdjksadhaisdy78o34y138974xyqp9rmye8yrpiokeuioqwzyoiuxftoyqiuxrhm3iou1hrzmjk"
end

# This is a barebone controller. One good reference can be found here:
# http://piotrsarnacki.com/2010/12/12/lightweight-controllers-with-rails3/
class HelloController < ActionController::Metal
  include ActionController::Rendering

  def world
    render :text => "Hello world!"
  end
end

# Initialize the app (originally in config/environment.rb)
MyApp.initialize!

# Print the stack for fun!
puts ">> Starting Rails lightweight stack"
Rails.configuration.middleware.each do |middleware|
  puts "use #{middleware.inspect}"
end
puts "run #{Rails.application.class.name}.routes"

# Run it (originally in config.ru)
run MyApp

Your Gemfile is Fat
Including too many libraries is bad for weight of the app. You need to check your Gemfile, and make sure you do require gems like ‘pry’ only in :development group, ‘rspec’ in :test etc.

There is general tendency of Rails developers of putting together applications together with ready-to-use blocks. You need to consider if that is what you really need. Writing simple authentication is a matter of controller and two actions, you might not need Devise for that. Handling simple file uploads can be almost as easily implemented as with use of Carrierwave, with much less boilerplate code. I do encourage you to build minimal solutions for your needs only, especially when you do not need to use majority of functionality provided by given gem. If there is a hole found in, say, Carrierwave, including the gem might make your application vulnerable too, and heavier than it needs to be, of course.

Gemfile
1
2
3
4
5
6
7
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
source 'https://rubygems.org'

gem 'rails', '~> 4.2.1'

gem 'psych', '~> 2.0.12'
gem 'builder'
gem 'dynamic_form'
gem 'aws-sdk-core'
gem 'gchartrb', require: 'google_chart'
gem 'gravtastic'
gem 'high_voltage'
gem 'highline'
gem 'honeybadger', '~> 1.0'
gem 'jquery-rails'
gem 'mail'
gem 'dalli'
gem 'multi_json'
gem 'paul_revere'
gem 'pg'
gem 'rack'
gem 'rdoc', '~> 3.12.2'
gem 'redis'
gem 'rest-client', require: 'rest_client'
gem 'statsd-instrument', '~> 2.0.6'
gem 'unicorn'
gem 'validates_formatting_of'
gem 'will_paginate'
gem 'xml-simple'
gem 'yajl-ruby', require: 'yajl'
gem 'autoprefixer-rails'
gem 'clearance'
gem 'daemons'
gem 'delayed_job'
gem 'delayed_job_active_record'

gem 'newrelic_rpm'
gem 'newrelic-redis'

gem 'sass-rails',   '~> 5.0.0'
gem 'coffee-rails', '~> 4.0.0'
gem 'uglifier', '>= 1.0.3'

group :development do
  gem 'capistrano', '~> 2.0'
  gem 'capistrano-notification'
  gem 'rails-erd'
end

group :test do
  gem 'minitest', require: false
  gem 'capybara'
  gem 'factory_girl_rails'
  gem 'launchy'
  gem 'rack-test', require: 'rack/test'
  gem 'rr', require: false
  gem 'shoulda', require: false
  gem 'timecop'
end

group :recovery do
  gem "fakeredis"
end

platforms :jruby do
  gem 'jruby-openssl'
end

So far so good, That’ it!!! See ya!!! :)

Ruby on Rails Pagination With Kaminari

Ruby on Rails Pagination with Kaminari

The will_paginate gem has long since been the most popular gem used when it comes to pagination. However it is not the only gem out there. Kaminari is another very popular pagination gem. In this article we will show you how to use it in your application.

Setup Rails Application
To begin using the kaminari gem, we must first add it to our Gemfile. Open up your Gemfile and add in the line listed below.

Gemfile
1
gem 'kaminari'

Now run a bundle install to install the gem.

1
bundle install

Next, create a model called Post. The post model in this example will represent a blog post. Run the commands below to create the post model:

1
2
rails g model Post title body:string
rake db:migrate

We need some seed data. Open your db/seeds.rb file and modify it so that it looks like the code listed below:

db/seeds.rb
1
2
3
4
5
(1..100).each do |i|
  Post.create!(title: "Lipsum Post #{i}", body: %{
      Nullam hendrerit iaculis sodales. Curabitur varius nibh arcu, id molestie nibh fermentum vitae. Cras quis semper dui. Cras porttitor urna sit amet risus vehicula tempor. Maecenas quis tempor ligula. Donec et nibh eu leo volutpat placerat. Fusce vulputate elit in nisi pretium, vel fermentum mi fermentum. Mauris scelerisque, lectus non luctus ultricies, urna eros tincidunt risus, at varius sapien diam id erat.
  })
end

Now run a rake db:seed to add the seed data:

1
rake db:seed

We need to add a controller called Posts that we will use to render the posts. Run the command below to create this controller now:

1
rails g controller Posts index

Let’s modify our routes file to set a site root. Open up your config/routes.rb file and modify it so that it looks like the code listed below.

config/routes.rb
1
2
3
Rails.application.routes.draw do
  root to: "posts#index"
end

Open up your Posts controller and modify it so that it looks like the code listed below.

app/controllers/posts_controller.rb
1
2
3
4
5
class PostsController < ApplicationController
  def index
    @posts = Post.page(params[:page]).per(10)
  end
end

As you can see, the first bit of our pagination code is here. The page method tells kaminari what page we are on. The per method tells kaminari how many items we wish to have per page.

Let’s open up the index view for our Posts controller and modify it so that it looks like the code listed below:

app/views/posts/index.html.erb
1
2
3
4
5
6
7
8
9
10
11
<h1>Posts</h1>
<hr />
<% @posts.each do |post| %>
  <h2><%= post.title %></h2>
  <p>
  <%= post.body %>
  </p>
<% end %>
<hr />
<%= paginate @posts %>
<%= page_entries_info @posts %>

The paginate helper is the line actually responsible for rendering the pagination links. The page_entries_info helper displays a line similar to Displaying posts 1 - 10 of 100 in total. This can be extremely helpful in letting the user know how many items there are in the list.

Global Configuration
You can also specify global defaults for Kaminari. First, run the following command to generate an initializer file for Kaminari:

1
rails g kaminari:config

If you open up the config/initializers/kaminari_config.rb file you’ll see something similar to the following:

config/initializers/kaminari_config.rb
1
2
3
4
5
6
7
8
9
10
Kaminari.configure do |config|
  # config.default_per_page = 25
  # config.max_per_page = nil
  # config.window = 4
  # config.outer_window = 0
  # config.left = 0
  # config.right = 0
  # config.page_method_name = :page
  # config.param_name = :page
end

A description of these options can be found below:

Config Description
config.default_per_page Specifies the default amount of items to display per page.
config.max_per_page The maximum amount of items to display per page.
config.window Specifies the inner window size. The inner window is the number of items in the middle of the pagination block. e.g. « First ‹ Prev … 1 2 3 4 … Next › Last », in the previous example, 1 2 3 4 would be considered the inner window.
config.outer_window Specifies how many items to display in the outer window. For example: 1 2 3 4 … 8 9 10 11, numbers visible on the outside are the outer window.
config.left Specifies how many items should be displayed in the left outer window.
config.right Specifies how many items should be displayed in the right outer window.
config.page_method_name Changes the page method name from page to whatever you want. Can be used to avoid conflict with other gems that use page.
config.param_name The default parameter to use when looking for the page number.

I18N
Kaminari can be configured via I18N. The default I18N configuration file looks like the code listed below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
en:
  views:
    pagination:
      first: "&laquo; First"
      last: "Last &raquo;"
      previous: "&lsaquo; Prev"
      next: "Next &rsaquo;"
      truncate: "&hellip;"
  helpers:
    page_entries_info:
      one_page:
        display_entries:
          zero: "No %{entry_name} found"
          one: "Displaying <b>1</b> %{entry_name}"
          other: "Displaying <b>all %{count}</b> %{entry_name}"
      more_pages:
        display_entries: "Displaying %{entry_name} <b>%{first}&nbsp;-&nbsp;%{last}</b> of <b>%{total}</b> in total"

To override it, simply modify your locale files under config/locales.

So far so good, That’s it!!! See ya!!! :)

Ruby/Ruby on Rails Mistakes

Ruby/Ruby on Rails Mistakes

Software Engineer make mistakes. Some of them are just annoying (for others to read) and some are really dangerous. Here is my selection of 10 mistakes done by Ruby / Ruby on Rails developers. These tips are easy to follow and can save you much time of later debugging.

Double Negative and Complex Conditionals

1
2
3
4
5
6
7
8
9
10
11
if !user.nil?
  # ...
end

unless user.blank?
  # ...
end

unless user.active? || address.confirmed?
  # ...
end

Double negative is hard to read. Every time I encounter it, I spend a couple of seconds on parsing the condition. Use the API which Rails gives you user.present? instead of !user.blank?.

I also rarely see any usage for unless, especially with complex conditionals connected by && and ||. How fast can you decide when unless user.active? || address.confirmed? will fire?

Using Save Instead of save! and Not Checking Return Value

1
2
3
user = User.new
user.name = "John"
user.save

What is wrong with this piece of code? It will fail silently when user cannot be saved. There will be no single trace of this failure in your logs and you will spend time wondering: “why there are no users in the database”. If you expect that data is valid and model should be always saved successfully, then use bang versions – save!, create! and so on. Use save only when you handle the return value:

1
2
3
4
5
if user.save
  # ...
else
  # ...
end

self When It’s Not Needed

1
2
3
4
5
6
7
8
class User
  attr_accessor :first_name
  attr_accessor :last_name

  def display_name
    "#{self.first_name} #{self.last_name}"
  end
end

In this case writing self.first_name is completely unnecessary, because first_name will do. This is of course just matter of style and has no other negative consequences than overly verbose code. Please mind that you need self in assignments: self.first_name = "John".

N + 1 Queries
This is a vast topic, but I will try to give the simplest example. You want to display a list of posts with names of authors. Post model belongs_to :user. If you just do Post.limit(10) and then call post.user.name in your views, you will make a separate database query for each user. That’s because Rails has no single chance to guess that you need users when you make the first query in the controller.

It’s easy to spot N + 1 queries problem just by looking at server’s logs:

1
2
3
4
5
6
7
8
9
10
11
12
13
Template Load (0.4ms)  SELECT  "templates".* FROM "templates"   ORDER BY "templates"."id" desc LIMIT 30 OFFSET 0
  Collection Load (0.2ms)  SELECT  "collections".* FROM "collections"  WHERE "collections"."id" = ? LIMIT 1  [["id", 1]]
  Collection Load (0.1ms)  SELECT  "collections".* FROM "collections"  WHERE "collections"."id" = ? LIMIT 1  [["id", 6]]
  CACHE (0.0ms)  SELECT  "collections".* FROM "collections"  WHERE "collections"."id" = ? LIMIT 1  [["id", 6]]
  CACHE (0.0ms)  SELECT  "collections".* FROM "collections"  WHERE "collections"."id" = ? LIMIT 1  [["id", 6]]
  Collection Load (0.1ms)  SELECT  "collections".* FROM "collections"  WHERE "collections"."id" = ? LIMIT 1  [["id", 3]]
  CACHE (0.0ms)  SELECT  "collections".* FROM "collections"  WHERE "collections"."id" = ? LIMIT 1  [["id", 3]]
  Collection Load (0.1ms)  SELECT  "collections".* FROM "collections"  WHERE "collections"."id" = ? LIMIT 1  [["id", 2]]
  CACHE (0.0ms)  SELECT  "collections".* FROM "collections"  WHERE "collections"."id" = ? LIMIT 1  [["id", 2]]
  CACHE (0.0ms)  SELECT  "collections".* FROM "collections"  WHERE "collections"."id" = ? LIMIT 1  [["id", 2]]
  CACHE (0.0ms)  SELECT  "collections".* FROM "collections"  WHERE "collections"."id" = ? LIMIT 1  [["id", 1]]
  CACHE (0.1ms)  SELECT  "collections".* FROM "collections"  WHERE "collections"."id" = ? LIMIT 1  [["id", 1]]
  Collection Load (0.1ms)  SELECT  "collections".* FROM "collections"  WHERE "collections"."id" = ? LIMIT 1  [["id", 4]]

You have to be explicit at telling what you need from the database. In the easy cases Rails includes method will do. You can read more about it in Rails guides - Eager Loading

Boolean Field with Three Possible Values
Boolean is supposed to have two possible values – true and false, right? And how about nil? If you do not specify default value and null: false in your migrations, you end up with boolean field with three possible values – true, false and nil. This leads to nasty code like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# post is new, not published, not rejected
if post.published.nil?
  # ...
end

# post is published
if post.published
  # ...
end

# post is new or rejected
unless post.published
  # ...
end

If you need three possible states – use string field with three well-defined values.

Orphaned Records After Destroy
When you destroy a model and it is required by associated records, you should handle it. It’s easy to find such cases:

1
2
3
4
class Post < ActiveRecord::Base
  belongs_to :user
  validates_presence_of :user
end

User is required for post. Hence, we have to write:

1
2
3
class User < ActiveRecord::Base
  has_many :posts, dependent: :destroy
end

Leaving puts
Leaving puts in the code after some debugging session pollutes server logs and output of tests. Use Rails.logger.debug so it’s later possible to adjust the desired log level.

Not Using map
I’ve seen such code many times:

1
2
3
4
5
users = []

posts.each do |post|
  users << post.user
end

This is exactly the case for using map, which is shorter and more idiomatic:

1
2
3
users = posts.map do |post|
  post.user
end

Not Using Hash#fetch

1
name = params[:user][:name]

What’s wrong with this code? It will throw NoMethodError: undefined method `[]' for nil:NilClass if there is no user key in the hash. If you expect the key to always be present, use Hash#fetch:

1
name = params.fetch(:user)[:name]

This will give you a meaningful exception – KeyError: key not found: :user.

Using Code from app/ in Migrations
Let’s say you have the following model:

1
2
3
class User < ActiveRecord::Base
  ACTIVE = "after_registration"
end

and you want to add points field to it. So you create a migration. But you would also like to handle existing users: 10 points for active and 0 for the rest. You add to your migration:

1
User.where(status: User::ACTIVE).update_all(points: 10)

It works and you are happy. Time passes by and you decide to remove User::ACTIVE constant. Your migrations are now broken, you cannot run them from scratch, because User::ACTIVE is undefined.

Never use code from app/ directory in migrations. If you need to update existing data and do it in a few environments (development, staging, production) create a Rake task and delete it once it’s executed in every environment.

So far so good, That’s it!!! See ya!!! :)

Fast Rails API With Rails-api and Active_model_serializers

Fast Rails API with Rails-api and Active_model_serializers

Dealing with JSON in Rails is pretty easy and straight forward. The support is built into the framework, request data is automatically available in params hash. Then we just have to say render :json and we are done.

If JSON is one of the formats which we use. For instance, we can render both JSON and HTML in the same controller action. Or we may create an action intended for AJAX call which changes some model and returns JSON with status field.

On the other hand, we may use Ruby on Rails for building JSON API – app with the assumption that JSON is the only format we support. In such a case we know that the app won’t render HTML. There is no View layer (or you can say that JSON is your View layer). We probably won’t need cookies support and the code specific to handling browser requests.

Rails-API

Ruby on Rails has modular structure – you can opt out of the things which you don’t want to use. But if we are talking about API only Rails app already did it for us and published in the gem called rails-api.

What I care is “Don’t require things which you won’t use”. There might be bugs hiding there or security vulnerabilities connected with it. And of course there are other reasons:

More Lightweight Application
I generated two fresh applications – one using rails-api new and the second using rails new. The environment was consistent – Ruby 2.1.0, Rails 4.0.2. Then I started the server with rails s and measured RAM memory taken by server process. The results are following:

This is 15% less. Obviously when you start adding new gems the relative difference will be smaller.

Faster Application
The same benchmarking environment as above. I created controller action which loads 100 User records from the database and renders them as JSON. I placed exactly the same code in rails-api application and regular rails application. Then I measured the server response time for a bunch of requests and took the avarage value. It looks like:

This is 12% faster.

Useful Generator
The controller scaffold which comes with rails-api is really cool. It disables new and edit actions (they don’t make sense because we do not display forms) and provides sensible default code inside other actions.

Easy Installation and No Maintenance Costs
Last but not least, rails-api is super easy to install and learn. All you have to do to bootstrap new app is:

1
2
gem install rails-api
rails-api new my_app

It’s worth to spend 10 minutes of your time for learning it. Check out the docs.

Active Model Serializers

If you want to build JSON API it’s good to have control over the generated JSON. And here we need the second gem is active_model_serializers.

Let’s look at a sample serializer:

app/serializers/user_serializer.rb
1
2
3
4
5
6
class UserSerializer < ActiveModel::Serializer
  attributes :id, :first_name, :last_name, :email

  has_one :address
  has_many :packages
end

As you can see UserSerializer is used to serialize User model. Using attributes we define what should be included in the generated JSON. You may think that this is repeating yourself (the fields are already defined in database schema), but in my opinion you rarely render all the fields, more often you want to hide some internals.

As you can see we embed associated records using familiar syntax: has_one and has_many. Serializing Address and Package will be handled using AddressSerializer and PackageSerializer, respectively.

app/serializers/user_serializer.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class UserSerializer < ActiveModel::Serializer
  [...]

  attributes :full_name, :email_address

  def full_name
    "#{object.first_name} #{object.last_name}"
  end

  def email_address
    object.email
  end

  [...]
end

Serializers are just classes which inherit from ActiveModel::Serializer. You can define regular methods and the model being serialized is accessed by object method.

How does the code inside UsersController look like?

app/controllers/users_controller.rb
1
2
3
4
5
6
7
8
9
[...]

  def index
    @users = User.includes(:address, :packages)

    render json: @users
  end

[...]

Pretty simple, You just say: “I want JSON” and you have JSON rendered with proper serializer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
  "users":
    [
      {
        "id": 1,
        "first_name": "Some String",
        "last_name": "Another String",
        [...]
        "address": { "street": "Yet another string" },
        "packages": [
          { "id": 2, "status": "delivered" },
          { "id": 5, "status": "lost" }
        ]
      }
    ]
}

More about Associations
Let’s imagine following use case, we want to get information about a package given its id. And we want it to contain information about the owner (user).

package_serializer.rb
1
2
3
4
5
class PackageSerializer < ActiveModel::Serializer
  attributes :id, :status

  has_one :user
end

What’s different here from model code? Package belongs_to user, but here it says has_one user. From the point of view of serializers belongs_to is exactly the same as has_one, hence we have only has_one and has_many.

Now let’s go back to UsersController#index after our changes. We hit the action again and what do we get this time?

1
2
3
Failure/Error: Unable to find matching line from backtrace
  SystemStackError:
    stack level too deep

That’s an infinite loop: user contains package, package contains user, user contains package… How can we solve this?

Solution 1

user_serializer.rb
1
2
3
4
5
6
7
class UserSerializer < ActiveModel::Serializer
  [...]

  has_many :packages, :embed => :ids

  [...]
end
1
2
3
4
5
6
7
8
9
10
{
  "users":
    [
      {
        "id": 1,
        [...]
        "package_ids": [2, 5]
      }
    ]
}

We can use :embed option and include only ids of the packages. This has a drawback: if a client of our API wants not only id of the package, but also its status then he will have to make a separate request for each package. Certainly this is a situation which we want to avoid.

Solution 2

user_serializer.rb
1
2
3
4
5
6
7
class UserSerializer < ActiveModel::Serializer
  [...]

  has_many :packages, :serializer => ShortPackageSerializer

  [...]
end
short_package_serializer.rb
1
2
3
class ShortPackageSerializer < ActiveModel::Serializer
  attributes :id, :status
end

We use :serializer option to specify different serializer than that inferred from naming conventions. We create ShortPackageSerializer, which doesn’t contain user embeded. What’s more you can put ShortPackageSerializer and PackageSerializer in the inheritance hierarchy so you DRY.

In my opinion this solution is pretty clean. We have separate class for each representation and we are able to share some pieces of code by using inheritance. Of course, this may become too complex if the inheritance hierarchy grows very big. However if we limit ourselves to 2-3 serializers per model the code should stay clear and maintainable.

Use rails-api if you are building API-only application. It’s easy to learn and maintenance won’t hit you later, because you can opt out without any problems.

Use active_model_serializers for better control over the generated JSON.

Fast Rails API

Fast Rails API

Rendering JSON is pretty easy in Rails.

1
render json: @statuses

It works well if there are small number of records to be returned. But what happens when we need to return 10,000 records at once? Things slow down dramatically and the most time-consuming parts are JSON serialization and database operations.

Include only Required Attributes
The first obvious thing is generating JSON with only attributes that we need.

1
render json: @statuses, methods: [:latitude, :longitude, :timestamp, :virtual_odometer]

Tidying JSON gives over 20% performance

1
2
default    5.940000   0.080000   6.020000 (  6.094221)
attrs      4.820000   0.010000   4.830000 (  4.932337)

Select only Required Columns
Second, we should consider selecting only required columns when we don’t need all of them.

1
render json: @statuses.select([:latitude, :longitude, :timestamp, :virtual_odometer])

It’ll help us to avoid transferring a huge amount of data to the application from the database and gives 2x speed up.

1
2
3
default    5.940000   0.080000   6.020000 (  6.094221)
attrs      4.820000   0.010000   4.830000 (  4.932337)
select     2.170000   0.020000   2.190000 (  2.222277)

Don’t Instantiate ActiveRecord Objects If Possible
Let’s implement a method to return “lightning” array of hashes instead of ActiveRecord instances.

1
2
3
4
5
6
7
def self.lightning
  connection.select_all(select([:latitude, :longitude, :timestamp, :virtual_odometer]).arel).each do |attrs|
    attrs.each_key do |attr|
      attrs[attr] = type_cast_attribute(attr, attrs)
    end
  end
end

Returns array of hashes instead of array of single column values. Invoke a new method in controller.

1
render json: @statuses.lightning

Using lightweight hashes makes JSON rendering 2x faster.

1
2
3
4
default    5.940000   0.080000   6.020000 (  6.094221)
attrs      4.820000   0.010000   4.830000 (  4.932337)
select     2.170000   0.020000   2.190000 (  2.222277)
lightning  1.120000   0.010000   1.130000 (  1.148763)

Fastest JSON

There are several JSON libraries available:
- JSON - The default JSON gem with C-extensions (ships with Ruby 1.9).
- YAJL - Yet Another JSON Library.
- OJ - Optimized JSON.

It’s a good idea to use the fastest dumper of them.

1
2
3
json       0.810000   0.020000   0.830000 (  0.841307)
yajl       0.760000   0.020000   0.780000 (  0.809903)
oj         0.640000   0.010000   0.650000 (  0.666230)

But we prefer active_model_serializers which it run faster than OJ.

Summarized benchmark results are:

1
2
3
4
5
6
7
8
9
user     system      total        real
default    5.940000   0.080000   6.020000 (  6.094221)
attrs      4.820000   0.010000   4.830000 (  4.932337)
select     2.170000   0.020000   2.190000 (  2.222277)
lightning  1.120000   0.010000   1.130000 (  1.148763)
json       0.810000   0.020000   0.830000 (  0.841307)
yajl       0.760000   0.020000   0.780000 (  0.809903)
oj         0.640000   0.010000   0.650000 (  0.666230)
ams        0.270000   0.000000   0.270000 (  0.272239)

So far so good, That’s it!!! See ya!!! :)

Preload Active Record Associations in Rails Application

Preload Active Record Associations in Rails Application

Active Record makes database querying so simple. Chain together a few methods and bam, you’ve saved your self lines and lines of T-SQL. The problem is this simplicity masks the underlying operation and it’s very easy to not realize how inefficient your database calls are.

For example:

1
2
3
4
5
6
7
8
9
10
11
12
class User < ActiveRecord::Base
  has_many :posts
end

class Post < ActiveRecord::Base
  has_many :comments
  belongs_to :user
end

class Comment < ActiveRecord::Base
  belongs_to :post
end

Let’s say on a users profile page we would like to show a listing of comments from this user.

1
2
3
4
5
6
7
@user = User.find(id)

@user.posts.each do |post|
   post.comments.each do |comment|
      <%= comment.message %>
   end
end

What you end up with is something like:

1
2
3
4
5
6
7
8
9
10
User Load (1.1ms)  SELECT `users`.* FROM `users` WHERE 'id' = 1 LIMIT 1
 Post Load (0.7ms)  SELECT `posts`.* FROM `blogs` WHERE `blogs`.`user_id` = 2
 Comment Load (0.7ms)  SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 43
 Comment Load (1.7ms)  SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 55
 Comment Load (2.2ms)  SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 32
 Comment Load (0.9ms)  SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 66
 Comment Load (2.2ms)  SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 56
 Comment Load (4.8ms)  SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 65
 Comment Load (1.8ms)  SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 68
 Comment Load (0.8ms)  SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` = 71

The user has commented in 9 different posts, which results in 9 separate queries to the DB. This is a small scale example, but you can see how this can compound into something nasty.

he solution is to user includes method:

1
@user = User.find(id).includes(:posts => :comments)

When using includes method, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries. The actual query executed is converted into a more optimal singular query and it is that result set that is iterated over instead of the replicated find(id) style queries.

Our query stack list now looks like:

1
2
3
User Load (1.0ms)  SELECT `users`.* FROM `users` WHERE 'id' = 1 LIMIT 1
Post Load (0.4ms)  SELECT `posts`.* FROM `posts` WHERE `posts`.`user_id` IN (1)
Comment Load (0.5ms)  SELECT `comments`.* FROM `comments` WHERE `comments`.`post_id` IN (43, 55, 32, 66, 56, 65, 68, 71)

So far so good, That’s it!!! See ya!!! :)

Where Does Your Code Go in Rails Application?

Where Does Your Code Go in Rails Application?

After you finish the Rails tutorials and start your own app, things get confusing something like where does your non-CRUD and general logic go?

You can’t build the app you’ve been dreaming of without some general, non-Rails logic. So where do you put your code, and still keep things simple?

The Easy Place to Start
when I have logic that feels related to an existing ActiveRecord model, I’ll start by putting it into that model. For example if I had a Game model and I want to import a bunch of games from CSV files, I would put that method right onto the Game class.

app/models/game.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Game < ActiveRecord::Base
  def self.parse_from_csv(csv_string)
    games = []
    CSV.parse(csv_string, quote_char: "'") do |row|
      games << Game.from_csv_row(row) if (row[0] == 'G')
    end
    games
  end

  def self.from_csv_row(row)
    Game.new({
      dgs_game_id: row[1],
      opponent_name: row[2],
      created_at: row[4],
      updated_at: row[4],
    })
  end
end

You have all the information your methods need right at hand. it’s easily testable. And it’s probably where a new contributor world look for that logic first.

But if you keep adding and changing that model, it’ll get big and complicated. Different parts of the model will interact in strange ways. The more you change it, the harder it will be to change.

In that case, you would probably want to refactor that code out to a non-ActiveRecord model.

Non-ActiveRecord Models
You can write your own Ruby code, in plain Ruby objects, and use them in your Rails app. These objects can still be called models, because they’re modeling part of your problem. They just don’t have an ActiveRecord database storing their data.

The next time I worked on that game CSV parser, the Game class was getting a little too big. So I moved the parser logic into its own GameCSVParser class.

Non-ActiveRecord class looks like:

app/models/game_csv_parser.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class GameCSVParser
  def initialize(csv_string)
    @rows = CSV.parse(csv_string, quote_char: "'")
  end

  def games
    game_rows.map { |row| Game.new(game_attributes(row)) }
  end

  private

  def game_rows
    @rows.select { |row| is_game_row?(row) }
  end

  def game_attributes(row)
    {
      dgs_game_id: row[1],
      opponent_name: row[2],
      created_at: row[4],
      updated_at: row[4],
    }
  end

  def is_game_row?(row)
    row[0] == 'G'
  end
end

I will go right to creating a new plain Ruby object if the logic I’m adding doesn’t feel related to any specific ActiveRecord model. Of if the code seems like it should be a part of a thing that doesn’t exist yet in the app. Otherwise, they mostly pop up through refactoring.

So far so good, That’s it!!! See ya!!! :)

Ruby on Rails Charting With Chartkick Gem

Ruby on Rails Charting with Chartkick Gem

Chartkick is a charting library for Ruby on Rails that allows you to easily create nice looking charts. Chartkick is compatible with all major browsers and can easily be used to give your Ruby on Rails application some additional flair. In this article we will cover the basics of using Chartkick.

Rails Application Setup
Before we can use Chartkick, we will need to add it to our Gemfile. Open up your Gemfile and add the following code.

Gemfile
1
gem 'chartkick', '~> 1.2.4'

In addition, let’s include a couple of helper gems that will make life easier when dealing with data. Add the following gems to your Gemfile.

Gemfile
1
2
gem 'groupdate', '~> 2.1.1'
gem 'active_median', '~> 0.1.0'

Now let’s run a bundle install to install all three gems.

1
bundle install

Now we need to create a model that we will use with our charts. For this example app we will create a simple model called Visit. This model will represent a single user’s ‘visit’ to a website. Run the command below to create this model now.

1
rails g model Visit country:string visited_at:datetime load_time:decimal

Now let’s run a rake db:migrate to create the table associated with this model.

1
rake db:migrate

Now we need to add some data to our seeds file in order to give us some data to play with. Open up your seeds.rb file and add in the code listed below.

db/seeds.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Visit.delete_all
Visit.create  country: 'United States', visited_at: DateTime.now, load_time: 3.5
Visit.create  country: 'United States', visited_at: DateTime.now, load_time: 1.5
Visit.create  country: 'United States', visited_at: DateTime.now, load_time: 1.0
Visit.create  country: 'United States', visited_at: DateTime.now - 1.day, load_time: 4.5
Visit.create  country: 'United States', visited_at: DateTime.now - 1.day, load_time: 4.0
Visit.create  country: 'United States', visited_at: DateTime.now - 2.days, load_time: 3.5
Visit.create  country: 'United States', visited_at: DateTime.now - 2.days, load_time: 1.0
Visit.create  country: 'United States', visited_at: DateTime.now - 2.days, load_time: 3.5
Visit.create  country: 'United States', visited_at: DateTime.now - 3.days, load_time: 4.5
Visit.create  country: 'United States', visited_at: DateTime.now - 3.days, load_time: 3.0
Visit.create  country: 'Germany', visited_at: DateTime.now, load_time: 1.0
Visit.create  country: 'Germany', visited_at: DateTime.now, load_time: 2.0
Visit.create  country: 'Germany', visited_at: DateTime.now, load_time: 1.0
Visit.create  country: 'Germany', visited_at: DateTime.now, load_time: 3.0
Visit.create  country: 'Germany', visited_at: DateTime.now - 1.day, load_time: 4.0
Visit.create  country: 'Germany', visited_at: DateTime.now - 2.days, load_time: 2.0
Visit.create  country: 'Germany', visited_at: DateTime.now - 2.days, load_time: 1.0
Visit.create  country: 'Germany', visited_at: DateTime.now - 2.days, load_time: 3.0
Visit.create  country: 'Germany', visited_at: DateTime.now - 3.days, load_time: 3.5
Visit.create  country: 'South Korea', visited_at: DateTime.now, load_time: 2.0
Visit.create  country: 'South Korea', visited_at: DateTime.now, load_time: 2.5
Visit.create  country: 'South Korea', visited_at: DateTime.now, load_time: 1.0
Visit.create  country: 'South Korea', visited_at: DateTime.now, load_time: 1.5
Visit.create  country: 'South Korea', visited_at: DateTime.now - 1.day, load_time: 2.5
Visit.create  country: 'South Korea', visited_at: DateTime.now - 1.day, load_time: 4.0
Visit.create  country: 'South Korea', visited_at: DateTime.now - 1.day, load_time: 3.0
Visit.create  country: 'South Korea', visited_at: DateTime.now - 2.days, load_time: 1.0
Visit.create  country: 'South Korea', visited_at: DateTime.now - 3.days, load_time: 5.0
Visit.create  country: 'South Korea', visited_at: DateTime.now - 3.days, load_time: 4.0
Visit.create  country: 'South Korea', visited_at: DateTime.now - 3.days, load_time: 5.0

Now let’s run a rake db:seed to seed our database.

1
rake db:seed

Now let’s create a controller to give us a place to play around. Run the commands below to create the Homes controller.

1
rails g controller homes show

Now open up your routes file and add in the route listed below.

1
2
3
Rails.application.routes.draw do
  root to: "homes#show"
end

Next, open up your homes controller and modify it so that it looks like the code listed below.

app/controllers/homes_controller.rb
1
2
3
4
5
class HomesController < ApplicationController
  def show
    @visits = Visit.all
  end
end

Finally, we need to modify our application layout. Open up your application’s layout and modify it so that it looks like the following code. Note the inclusion of the Google API javascript file below. Chartkick can use either Google Charts or Highcharts for charting. In this example we use Google Charts. We also utilize Bootstrap for a cleaner look and feel.

app/views/layouts/application.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html>
<head>
  <title>ChartKickExample</title>
  
  <%= stylesheet_link_tag    'application', media: 'all' %>
  <%= javascript_include_tag 'application' %>
  <%= javascript_include_tag "http://www.google.com/jsapi", "chartkick" %>
  <%= stylesheet_link_tag 'http://yandex.st/bootstrap/3.1.1/css/bootstrap.min.css' %>
  <%= javascript_include_tag 'http://yandex.st/bootstrap/3.1.1/js/bootstrap.min.js' %>
  
  <%= csrf_meta_tags %>
</head>
<body>
  <div class="container">
    <%= yield %>
  </div>
</body>
</html>

Line Charts
The first chart type we will work with is the line charts Line charts are handy for doing things like plotting out events over time. Open up your show view for the Homes controller and modify it so that it looks like the code listed below.

app/views/homes/show.html.erb
1
2
3
4
5
6
7
8
9
<div class="row">

  <!-- Line Chart - Single Series -->
  <div class="col-xs-6">
    <h3>Visits By Day</h3>
    <%= line_chart @visits.group_by_day(:visited_at, format: "%B %d, %Y").count, discrete: true %>
  </div>

</div>

Now if you start a rails s and navigate to http://localhost:3000 you will see a chart being rendered showing the number of vists by day.

Great, now lets make a slightly more complex line chart. Open up the show view again and modify it so that it looks like the code listed below.

app/views/homes/show.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div class="row">

  <!-- Line Chart - Single Series -->
  <div class="col-xs-6">
    <h3>Visits By Day</h3>
    <%= line_chart @visits.group_by_day(:visited_at, format: "%B %d, %Y").count, discrete: true %>
  </div>

  <!-- Line Chart - Multiple Series -->
  <div class="col-xs-6">
    <h3>Visits By Country Per Day</h3>
    <%= line_chart   Visit.pluck("country").uniq.map { |c| { name: c, data: @visits.where(country: c).group_by_day(:visited_at, format: "%B %d, %Y").count }  }, discrete: true %>
  </div>

</div>

Refreshing the page results in a new line chart with multiple series listed. You see a line for each country with each point corresponding to the number of visits for that day.

Pie Charts and Area Charts
We can also render a pie chart. Open up your show view again and append the following code to the end of the view.

app/views/homes/show.html.erb
1
2
3
4
5
6
<div class="row">
  <div class="col-xs-6">
    <h3>Total Visits by Country</h3>
    <%= pie_chart @visits.group(:country).count %>
  </div>
</div>

If you refresh the page a pie chart will render with each slice representing the visits for that particular country. This information can also be represented via a geo chart. Modify your homes view to look like the code listed below.

app/views/homes/show.html.erb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<div class="row">

  <!-- Line Chart - Single Series -->
  <div class="col-xs-6">
    <h3>Visits By Day</h3>
    <%= line_chart @visits.group_by_day(:visited_at, format: "%B %d, %Y").count, discrete: true %>
  </div>

  <!-- Line Chart - Multiple Series -->
  <div class="col-xs-6">
    <h3>Visits By Country Per Day</h3>
    <%= line_chart   Visit.pluck("country").uniq.map { |c| { name: c, data: @visits.where(country: c).group_by_day(:visited_at, format: "%B %d, %Y").count }  }, discrete: true %>
  </div>

</div>

<div class="row">

  <!-- Pie Chart -->
  <div class="col-xs-6">
    <h3>Total Visits by Country</h3>
    <%= pie_chart @visits.group(:country).count %>
  </div>

  <!-- Geo Chart --> 
  <div class="col-xs-6">
    <h3>Visits By Day</h3>
    <%= geo_chart @visits.group(:country).count %>
  </div>

</div>

Awesome! Now if you refresh the page, you’ll notice a geo chart in the bottom right.

Area Charts
You can also create an area chart. Add the code listed below to the end of your homes/show view.

app/views/homes/show.html.erb
1
2
3
4
5
6
7
<!-- area chart -->
<div class="row">
  <div class="col-xs-12">
    <h3>Total Load Time By Day</h3>
    <%= area_chart @visits.group_by_day(:visited_at).maximum(:load_time) %>
  </div>
</div>

Great, now if you refresh the page you will see that the area chart has been added.

Bar Charts and Column Charts
Both bar charts and column charts can be easily created. Modify your homes/show view so that it looks like the code listed below.

app/views/homes/show.html.erb
1
2
3
4
5
6
7
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
<div class="row">

  <!-- Line Chart - Single Series -->
  <div class="col-xs-6">
    <h3>Visits By Day</h3>
    <%= line_chart @visits.group_by_day(:visited_at, format: "%B %d, %Y").count, discrete: true %>
  </div>

  <!-- Line Chart - Multiple Series -->
  <div class="col-xs-6">
    <h3>Visits By Country Per Day</h3>
    <%= line_chart   Visit.pluck("country").uniq.map { |c| { name: c, data: @visits.where(country: c).group_by_day(:visited_at, format: "%B %d, %Y").count }  }, discrete: true %>
  </div>

</div>

<div class="row">

  <!-- Pie Chart -->
  <div class="col-xs-6">
    <h3>Total Visits by Country</h3>
    <%= pie_chart @visits.group(:country).count %>
  </div>

  <!-- Geo Chart --> 
  <div class="col-xs-6">
    <h3>Visits By Day</h3>
    <%= geo_chart @visits.group(:country).count %>
  </div>

</div>

<!-- area chart --> 
<div class="row">
  <div class="col-xs-12">
    <h3>Total Load Time By Day</h3>
    <%= area_chart @visits.group_by_day(:visited_at).maximum(:load_time) %>
  </div>
</div>

<div class="row">
  <!-- Column Chart -->
  <div class="col-xs-6">
    <h3>Total Visits Per Country</h3>
    <%= column_chart @visits.group(:country).count %>
  </div>
  <!-- Bar Chart -->
  <div class="col-xs-6">
    <h3>Total Visits Per Country</h3>
    <%= bar_chart @visits.group(:country).count %>
  </div>
</div>

If you refresh the page you’ll see both column and bar charts at the bottom.

Remote Charts
You can quickly and easily build remote AJAX driven charts. Let’s create a simple series chart. First, we will create a new method on your homes controller called visits_by_day. Open up your homes controller and modify it so that it looks like the code listed below.

app/controllers/homes_controller.rb
1
2
3
4
5
6
7
8
9
class HomesController < ApplicationController
  def show
    @visits = Visit.all
  end

  def visits_by_day
   render json: Visit.group_by_day(:visited_at, format: "%B %d, %Y").count
  end
end

Next, add in the code listed below to your homes/show view.

app/views/homes/show.html.erb
1
2
3
4
5
<!-- Line Chart - Single Series -->
<div class="col-xs-12">
  <h3>Visits By Day</h3>
  <%= line_chart visits_by_day_home_path %>
</div>

If you refresh the page, you’ll notice that the new chart has been rendered. A quick look at your browser’s developer console will show you that the visits_by_day data is pulled down via AJAX and then the site is rendered.

Global Options
You can customize the global options for ChartKick. Create an initializer called chartkick.rb and add in the code listed below.

config/initializers/chartkick.rb
1
2
3
4
Chartkick.options = {
  height: "300px",
  colors: ["#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "0000ff"]
}

If you restart your Rails server and refresh the page, you will notice that the colors have changed.

For more information on ChartKick you can check Chartkick.

So far so good, That’s it!!! See ya!!! :)

Automatically-updating Timeago Text With Rails-livestamp Gem

Automatically-updating Timeago Text with rails-livestamp Gem

rails-livestamp is a simple jQuery plugin that makes it easy to provides automatically updating text to your timestamped HTML elements.

Installation
Add this line to your application’s Gemfile:

Gemfile
1
gem 'rails-livestamp', '~> 1.1.3'

And then execute:

1
bundle install

Or install it yourself as:

1
gem install rails-livestamp

To use rails-livestamp add this require statement to your application.js file:

application.js
1
//= require rails-livestamp

Usage
No extra JavaScript required! Just use a with the data-livestamp attribute set to the desired Unix timestamp (in seconds), like this:

If you use ERB:

1
You discovered rails-livestamp <span data-livestamp="#{Time.now.to_i}"></span>.

If you use HAML:

1
2
You discovered rails-livestamp
%span{"data-livestamp" => "#{Time.now.to_i}"}.

And you will see something like this:

1
You discovered rails-livestamp a minutes ago.

Wait half a minute - the livestamp will update automatically.