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.
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:
- Detect user’s device screen resolution
- 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:
- When user enters our website, we’ll use javascript to detect his device resolution.
- We’ll store that resolution in a cookie.
- 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!