Tag Archives: ruby on rails

Push Notifications for Mobile Apps

Sometimes we need to send push messages from our Web App to Mobile App subscribers.

Main Mobile OS providers offer their own services:

  1. Apple: APN (Apple Push Notifications): for Iphone
  2. Google: GCM (Google Cloud Messages): for Android and Iphone

If you have only an Iphone App you can use only APN. But if you will have both Iphone and Android Apps, it could be a good idea to talk with the iOS Developers about to use GCM, in order to simplify the final System (need to talk, maybe they have great arguments to use APN).

I found this great schema at androidhive.info:

gcm-a-modr

 

APN works similar. Our Rails server will need to:

  • (3) Create an API end-point which stores the registration_id
  • (a) Send push messages from our app

Our API can be ‘/v1/push_registration’ receiving a messages like:

{"apn_id" : "191434a07d17cad3446597e5ad7f1588"}
{"gcm_id" : "191434a07d17cad3446597e5ad7f1588"}

The second point can be resolved with a gem. Below we will analyze some solutions for that point.

Bot apn_on_rails and gcm_on_rails seems outdated, as the last commit happened in 2012, and there were many changes in Rails and in the APN/GCM services themselves.

gem gcm

This gem only supports the GCM service. But there is no problem with Iphone Apps because this service supports them.
Implementation:

  • Initialize object:
    require 'gcm'
    gcm = GCM.new("my_api_key")
  • Send a message:
    registration_ids= ["12", "13"] # an array of one or more client registration IDs
    options = {data: {message: "Hello World"}, collapse_key: "updated_score"}
    response = gcm.send(registration_ids, options)

gem push-core

This gem supports both services: GCM and APN.
Implementation:

  • We can initialize both services with their API keys:
    Push::ConfigurationApns.create(app: 'app_name', connections: 2, enabled: true,
        certificate: File.read('certificate.pem'),
        feedback_poll: 60,
        sandbox: false)
    Push::ConfigurationGcm.create(app: 'app_name', connections: 2, enabled: true,
        key: '')
  • Send a message:
    Push::MessageApns.create(
        app: 'app_name',
        device: '',
        alert: 'Hello World',
        sound: '1.aiff',
        badge: 1,
        expiry: 1.day.to_i,
        attributes_for_device: {key: 'MSG'})
    Push::MessageGcm.create(
        app: 'app_name',
        device: '',
        payload: { message: 'Hello World' },
        collapse_key: 'MSG')

gem rpush

This gem supports all push services we find in the market: APN, GCM, Windows and Amazon. And it is by far the most active, so seems the facto gem to deal with the current Push Notification feature in ruby world.
Implementation:

  • We can initialize both services with their API keys:
    app = Rpush::Gcm::App.new
    app.name = "android_app"
    app.auth_key = "..."
    app.connections = 1
    app.save!
  • Send a message:
    n = Rpush::Gcm::Notification.new
    n.app = Rpush::Gcm::App.find_by_name("android_app")
    n.registration_ids = ["..."]
    n.data = { message: "Hello World" }
    n.save!

 Conclusion

Rpush gem seems the best option because it supports all Push services, and is the most active gem in this area.

For your Rails App we will need (for our config file) the Application name and the auth_key.

Comparing Rate limiting solutions for a Rails App

In the ‘scary free internet’ we can have DoS attacks or simply a client who has an error using your APi sending thousands of requests in a minute. This could have bad effects in your application performance.

To avoid these effects we can implement this example in our web app: Every IP cannot make more than 10 requests per minute, from that limit we should reject the requests

gem ratelimit

Seems more oriented to count everything in the app:

  • Manually you create a Redis database when Rails starts:
@ip_ratelimit = Ratelimit.new("request_ip_limit_db")
  • You can check in order to send a Forbidden message:
@ip_ratelimit.exec_within_threshold request.remote_ip, threshold: 10, interval: 60 do
  render json: 'IP request limit overhead.', status: 403
end
  • Wherever you want in the controllers you can increment the counter:
@ip_ratelimit.add(request.remote_ip)

Features:

  • Based on local Redis database
  • You can count whatever target (not only IPs)
  • Implementation:
    • Make an initializer to setup Redis database
    • Make a filter in Application controller to increment IP counter

gem rack-throttle

Seems the easier, cleaner and faster ruby based solution for our example.

  • Configured at config/application.rb:
require 'rack/throttle'
require 'memcached'
class Application < Rails::Application
  config.middleware.use Rack::Throttle::Minute,   max: 10, cache: Memcached.new, key_prefix: :throttle
end

Features:

  • Memcached based (which makes it faster). You can user Redis also.
  • Only counts remote_host accesses (identified by default by Rack::Request#ip).
  • Strategies can be customized.
  • Cleaner in code because this represents a “Rack Layer”, not a “Controller Filter” which spread more the code all over our App.

Nginx ngx_http_limit_req_module

This is a fully implementation of the Leaky Bucket algorithm :

limit_req_zone $binary_remote_addr zone=one:10m rate=10r/m;
server {
    location / {
        limit_req zone=one burst=5;
    }

How it runs:

  • Reserving a 10Mbytes of shared memory
  • Limiting 10 request per minute
  • When it is overloaded (burst) 5 requests are delayed to the next minute.
  • When rate+burst is over, request is terminated with an error 503 (Service Temporarily Unavailable)

Other solutions

gem rack-attack:

  • Rack level solution
  • Implements Blacklists and Whitelists

How to Get Google to properly Index your Rails website

In order to be properly indexed by Google (and other search engines), we need to fix three basic values in the header: title, description and keywords. So in header layout we should include them as meta tags:

%title= content_for?(:title) ? yield(:title) : "Lebrijo.com - Internet applications Consultancy"
 %meta{content: content_for?(:description) ? yield(:description) : "We build high quality Internet application for our customers", name: "description"}
 %meta{content: content_for?(:keywords) ? yield(:keywords) : "ruby, ruby on rails, consultancy, webapps, developers", name: "keywords"}

Another useful thing is creating a /sitemap.xml file where Engine-bots see your app structure. We can use the sitemap_generator gem, just including it in our Gemfile.

I have created a rake task for auto generating it:

desc "Generates sitemap"
  namespace :sitemap do
  task :generate do
  SitemapGenerator::Sitemap.default_host = 'http://www.lebrijo.com'
  SitemapGenerator::Sitemap.create do
    add '/', changefreq: 'daily', priority: 0.9
    add '/', changefreq: 'daily', host: 'http://blog.lebrijo.com', priority: 0.8
    add '/', changefreq: 'weekly', host: 'http://jenkins.lebrijo.com'
    add '/about', changefreq: 'weekly'
    add '/contact', changefreq: 'weekly'
  end
  SitemapGenerator::Sitemap.ping_search_engines
  end
end

And a Capistrano task, auto-generating sitemap on all deployments:

namespace :sitemap do
  desc "Generate sitemap.xml"
  task :generate do
    on roles(:app) do
      within release_path do
        with rails_env: fetch(:stage) do
          execute :rake, 'sitemap:generate'
        end
      end
    end
  end
after "deploy:published", :generate
end

Finally be careful with your ‘robots.txt’ file configuration, because Google should be allowed to download and crawl your page.

Once everything is done and deployed in your application, just add it to Google WebMaster Tools. Don’t forget to add your sitemap.xml.gz URL.

Here you have a great link enumerating what other things you can do to improve your website SEO features.