28 5 / 2013

Benchmarking gem load times

There is an awesome gist written by Pan Thomakos, and later refined by Andrew Kane here: https://gist.github.com/ankane/5022636

Here is simple fish shell function that can be used to run this script in any project you need:

function benchmark_bundler
  set -x BUNDLE_GROUPS $argv
  curl -fsSL https://gist.github.com/raw/5022636/benchmark.rb | ruby
end

Just put it in your ~/.config/fish/config.fish file and off you go.

13 3 / 2013

Super fast way of launching postgres console for rails apps

Database console can be run with bundle exec rails dbconsole command. However, this operation performs relatively slow (due to bundler and deps).

We can make it much faster with simple ruby script:

#!/usr/bin/env ruby

require 'yaml'
require 'fileutils'

database_config = YAML.load_file(Dir.pwd + '/config/database.yml')['development'];
database_name = database_config['database']

exec('psql', "-d#{database_name}")

Just save the script somewhere in your $PATH and give it u+x permission.

I like to place scripts like these in my ~/dev/bin folder (included in $PATH). I gave this one db name, so the only thing i need to do to fire up postgres console is to type db. Simple and extremely fast.

29 12 / 2012

Rails consecutive migrations acting weird

If you’re using models in your database migrations, its good practice to define dummy active record clases for them:

class SomeMigration < ActiveRecord::Migration
  class User < ActiveRecord::Base
    reset_column_information
  end
  # ...
end

If you have many migrations to run and model definition changes over time (which is likely to happen), you need to call reset_column_information in order to “reload” the model on beginning of every migration.

27 10 / 2012

Attachinary v1.2.0 released

Changelog

  • Drag and drop support (on supported browsers)
  • Selecting multiple files (on supported browsers)
  • Upload progress indicator (prepended on submit button)
  • Rake task for fetching assets (rake attachinary:fetch_fileupload)
  • Ability to assing image urls (e.g. user.avatar_url = 'http://..')
  • Ability to assign IO objects (e.g. user.avatar = File.open(...))
  • No-JS support

10 9 / 2012

30 8 / 2012

Integrating Prefixr with Rails asset pipeline

Prefixr is cool online service created by Jeffrey Way for adding vendor prefixes to your css. It has nice and simple API to let you integrate it into your workflow. Here is how you can integrate it with Rails asset pipeline.

Just create prefixr.rb file inside config/initializers folder with following content:

require 'uri'
require 'net/http'

class PrefixrPostprocessor < ::Tilt::Template
  def prepare
  end

  def evaluate(context, locals, &block)
    uri = URI.parse "http://prefixr.com/api/index.php"
    Net::HTTP.post_form(uri, { css: data }).body
  end
end

Rails.application.assets.register_postprocessor 'text/css', PrefixrPostprocessor

It defines and registers postprocessor for text/css files. Now, every css file served through rails will be automatically prefixr’d! This will work even if you use sass or less!

The downside of this approach is that it will slow down the development because it will need to make HTTP request to prefixr.com API every time the css file is requested by browser. I wish that there is ruby version of prefixr service as a gem that I could just use directly inside PrefixrPostprocessor. That would be just awesome! Who knows.. maybe I just make one!

15 8 / 2012

Cachex: tag based fragment caching on steriods

I’ve just released another gem. Its called Cachex.

This gem is inspired by excellent Cashier gem. I wanted to take it a step further and try to automate tag dependency generation.

I had this scenario in mind:

  • Blog has many posts
  • Each post has an author (user)
  • Each post has many comments
  • Each comment has its own author (user)

Each model has its own partial. Inside _post partial we have _user partial that renders post’s author. _post partial also include many _comment partials. Each _comment partial have author’s name displayed in it.

We’re also using fragment caching in order to cache entire post for faster serving. The burning question is: what happens if user decides to change its name (or perhaps, more commonly, an avatar)?. We have to invalidate every cached partial that displayed that user. How do we do that?

If we’re using auto-expiring key strategy the only way to accomplish this would be to touch everything that has to do with that user. That just doesn’t make any sense.

If we’re using tag-based strategy, then we would need to manually tag every fragment with all users that have to do something with it (even users from its comments). Such approach is going to be very hard when we get to deeply nested partials. Top most partial will have to be aware of all dependencies down to the deepest one.

And finally, my solution: to automatically extract all dependencies from all sub-partials and to store them to help cache invalidation.

Read more on github.

Tags:

Permalink 1 note

15 6 / 2012

Testing API from Rails Console

Recently I created small API for one of my apps that is to be accessed by an iPhone application. I followed Railscasts guides on how to create, version, and secure it with access token. Even though you can test the api with CURL command, it tend to get a bit more complex when you need to specify token header every single time.

I wanted to be able to test the API in more simplistic way. I wanted it to be something like this:

api User.first, :get, '/api/projects'

Here is the simple helper method that can make this process much easier:

def api(user, method, url, params=nil)
  headers = {
    'Accept' => 'application/roommates.v1',
    'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Token.encode_credentials(user.api_token)
  }
  app.send(:"#{method}", url, params, headers)
  ap JSON.parse(app.response.body)
end

Method simply sets proper headers, issues request, pretty-prints returned json (with awesome_print gem), and returns it. You can customize any way you want.. this is just an idea of how it might look.

All you have to do is put this method in .irbrc file in your project root and it will be automatically loaded each time you start your rails console.

13 5 / 2012

Redis Marshaling

If you have time consuming method in your app that you call frequently, chances are that you’d like to cache it. Redis is great key-value store that can be used for this purpose. However, redis only store string values. In order to store other kinds of objects, you’ll have to use marshaling.

There is a built-in ruby class called Marshal that does the job well. The only thing you have to do is to call Marshal.dump method and pass it an object. The exact opposite is the Marshal.load method.

I’ve created helper method for easier integration with Redis. Here is how it looks:

module RedisHelper

  # Returns the cached value for given key.
  # If it doesn't exist, it evaluates the block and caches what it returns.
  # 
  # @param [String] key the cache key
  # @param [Hash] options
  # @option options [Integer, nil] :ttl time to live in seconds
  # @option options [Boolean, false] :marshal whether to perform marshaling
  # @yield [] to be evaluated if the key does not exist
  def self.fetch(key, options={}, &block)
    raise ArgumentError.new("Must Supply Block") unless block_given?
    return yield unless Rails.application.config.action_controller.perform_caching

    val = nil

    if REDIS.exists(key)
      val = REDIS.get(key)
      begin
        val = Marshal.load(val) if options[:marshal]
      rescue TypeError
        val = nil
      end
    end

    if !val
      val = yield

      if options[:marshal]
        REDIS.set key, Marshal.dump(val)
      else
        REDIS.set key, val
      end

      REDIS.expire key, options[:ttl] if options[:ttl]
    end

    val
  end

end

There is not much to describe here since its already documented using yard. Instead, I’ll show how I used in in one of my apps:

module Geocoder

  def self.geocode(location)
    key = "geolocations/#{location}"
    RedisHelper.fetch key, ttl: 24.hours, marshal: true do
      Geokit::Geocoders::GoogleGeocoder.geocode(location)
    end
  end

end

I’m using geokit gem for discovering geocoordinate of an address. It uses Google geocoding API which is limited to 2500 queries per day. This piece of code will cache the result of GoogleGeocoder.geocode method so all successive requests will be returned from cache.

18 4 / 2012

Responsive Images with Cloudinary on Rails

Responsive Images is a hot topic lately. There are few solutions to the problem: introduction of new html element (which will take years to be ready for use), new image format (which may take even more time), and using other technologies to solve the problem. Here, I’ll focus on the last one.

The goal is clear:

  1. Detect user’s device screen resolution
  2. Serve appropriate images for best browsing experience

In order to handle cases where you cannot detect user’s device capabilities (e.g. no javascript support), we need to provide reasonable defaults (e.g. medium sized images).

Here is how you can accomplish this in few simple steps by using Cloudinary service for hosting your assets.


The concept is simple:

  1. When user enters our website, we’ll use javascript to detect his device resolution.
  2. We’ll store that resolution in a cookie.
  3. Backend will utilize information inside cookie to serve appropriate image format.

First two steps are quite easy to do. All you have to do is inject following javascript

document.cookie='resolution='+screen.width+'x'+screen.height)+'; path=/';

That would store user’s device screen resolution in a cookie. On the next page load, that cookie will be available to your backend.

Now, lets override cloudinary cl_image_tag to allow :responsive option. You can do so by including this in application_helper file:

def cl_image_tag(source, options = {})
  if (sizes = options.delete(:responsive)) && (resolution = cookies[:resolution])
    res = case resolution.split('x').first.to_i
          when 0..480 then :phones
          when 481..767 then :tablets
          else :desktops
          end

    size = sizes[res]
    options[:size] = size if size
  end

  super(source, options)
end

Method simply checks whether :responsive option and :resolution cookie are present. If so, it replaces the :size parameter with appropriate value. The usage would be like this:

<%= cl_image_tag "sample.jpg", size: '200x200', crop: 'fit', 
    responsive: { phones: '50x50', tablets: '100x100' } %>

That would serve 50x50px image for phones, 100x100px version for tablets and fallback to 200x200px version for all others. Sweet!