Bambinos RSS

New Bamboo

Bamboo Blog

Archive

Nov
25th
Tue
permalink ismasan

Convention for ActiveRecord extensions

There’s not one but many ways of extending ActiveRecord. Some people do:

ActiveRecord::Base.send :include SomeModule

Which in turns includes or extends other modules.

Others extend first, and include internally. Others class_eval the hell out of everything.

There are a few gotchas to avoid, such as accidentally reloading the same modules (ie. in background tasks), which can cause havoc if your extensions uses method aliasing.

Looking at different approaches, I’ve come up with this draft of a convention. 

Here’s the gist of it.

Nov
19th
Wed
permalink dctanner
Nov
18th
Tue
permalink matthewcford

Build a bug tracker in 5 mins

  • Go to google docs, click new spread sheet
  • Click form, create your form with title, description, severity (1 minor .. 5 epic fail), who’s responsible in a dropdown and reported by.
  • Save your form
  • Add conditional colouring on severity
  • Add a completed/status column
  • Embed form onto a page/email form to bug hunters.

Nov
15th
Sat
permalink bartoszblimke

XP song

Nov
12th
Wed
permalink bartoszblimke
permalink bartoszblimke
permalink bartoszblimke

ActiveRecord.connection.execute and INSERT statement gotcha.

Today I was working with a more complex version of the following code using ActiveRecord:

             
        def find_or_create_user_by_id(id)
            begin
                 user = User.find(id)
            rescue 
                 User.connection.execute("INSERT INTO users (id ) VALUES(#{id})") 
                 user = User.find(id)
            end    
            return user
        end
    

What’s wrong with this?
The second User.find will throw ActiveRecord::RecordNotFound. The problem is that the execute method, doesn’t invalidate cache, so the second User.find will just hit cache (cache created by the first User.find) instead of hitting the database. To solve the problem I had to use User.connection.insert, it invalidates cache so the second User.find hits database. I was hardly able to find any documentation that would describe this behaviour.

permalink bartoszblimke

How to get remote_ip address in Rails application behind proxy.

To get the ip address of a client in rails application, you can call remote_ip method on request object. This works fine, unless your application is behind proxy which ip address doesn’t match the following regular expression:

    
    /^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./
    

If the proxy ip address is different, remote_ip will return ip address of the proxy. To fix this problem, you have to change the regular expression to match your proxy ip address and overwrite TRUSTED_PROXIES constant in AbstractRequest class in one of the application initializers. For example, if your proxy ip address is 201.202.203.204, you could use the following code:

    
    ActionController::AbstractRequest.const_set("TRUSTED_PROXIES", /^201\.202\.203\.204$|^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i)
    
Nov
4th
Tue
permalink ismasan

Test ActiveRecord schemas

I’m writing a gemified extension to ActiveRecord. I want a SQLite database to create a quick and dirty schema to test my finders. Yes, I’m lazy and can’t be bothered to write mocks. I want to be able to add or remove columns quickly while avoiding SQL (did I mention I’m lazy?)

Solution: create a SQLite file in your test folder, and the following rake task in your gem’s “tasks” directory (see embeded gist)

Use with:

rake db:create

Modify the schema in the migration definition and create again

Oct
30th
Thu
permalink matthewcford

Deleting Duplicates with Unique Keys in MySQL with Ruby

Trying to delete duplicate data is a pain. Especially when your table is bigger than your RAM available so you cannot just create a temp table can copy the unique rows back and forth.

So I’ve made available some code in this gist which will delete duplicate data, in the case where the ids are unique but the data is duplicated.

# USE: delete_dups_for(Comment, :post_id)

NB: code is at the bottom, the first 232 lines are the Ruby Progress Bar lib


Oct
13th
Mon
permalink rob-work

Remote Images and jQuery

I just got bitten by something really nasty, so thought I’d care to share…

Symptom

On a certain page, we are outputting 10 divs each of which contained a radio button and an image. In Safari, (and it turned out IE), each time I refreshed, only some of those 10 divs were rendered. Sometimes it would be 5, sometimes 8, sometimes none displayed at all - it all seemed to be completely random. However… the weird thing was that all 10 divs showed correctly in the source!

Problem 1: No indication that javascript was in use

For quite a while, I thought this was some very weird, and obscure browser issue with Safari. It turned out that the culprit for this very weird behaviour was a jQuery function being applied to the those divs which shared a common class.

Our normal best practice is to use classes starting with js_ for anything that we’re going to apply jQuery calls to. In this case, that wasn’t done, which led me down the proverbial garden path.

Problem 2: jQuery initialisation

Having figured out that javascript was in play, I found this jQuery function being applied:

var Bookmarks = {                                              
    init: function(){                                            
        $('div.candidate_image img').each(function(){              
            if (($(this).width() < 50) || ($(this).height() < 50)) { 
                $(this).parent().hide();                               
            }                                                   
        });                                                       
    }                                                           
};                                                             

It hides those divs where the contained image is less than 50px in either dimension, and was being called where we initialised all our other jQuery stuff in a block like this:

// initialisers go here
$(document).ready(function(){
    ...
    Bookmark.init();
    ...
}

The problem is, the images were remote images stored on other servers, and took a while to load. Therefore when the Bookmarks.init function was called, some of the images wouldn’t yet have been loaded fully from the remote sites, and therefore had width: 0, height: 0. This is why the divs would randomly be displayed or not, because it depended on whether the images had managed to load fully.

Solution

The way round this, is to put the Bookmark.init() inside a load() handler, instead of the ready() one, like this:

$(document).load(function(){
    ...
    Bookmark.init();
    ...
}

This gets run once everything has been loaded (including images), rather than just when the DOM structure is ready.

Sep
30th
Tue
permalink gwyn

Regex to detect non-ascii

[^a-zA-Z0-9,()\s.-"'\;+!_\/:*\%\?]

Sep
25th
Thu
permalink ismasan

Normalize params

Sometimes we need to make sure there is a key in the params hash, even when it’s not defined in the routes.rb file.

Ie. params[:page]. Instead of validating it in separate actions, just make sure it’s there in a before_filter

before_filter :normalize_params

protected

def normalize_params
params[:page] ||= 1
# some more normalization if needed
end


Then you can be confident that it exists:

def	index
 @products = Product.paginate(:all, :page => params[:page] )
end


Of course the ideal solution is to have default parameters in the routes file, but not always possible.

Sep
17th
Wed
permalink ollylegg
Sep
16th
Tue
permalink ismasan

Equal column height

You have several HTML columns and you want them to be the same height. Problem is, the content is dynamic so you don’t know what the actual height will be.

This jQuery bit resolves the highest column and applies it to all columns in the group.

;(function($){

$.fn.equalHeight = function(){
var max_height = 0;
$(this).each(function(){
var h = $(this).height();
if(h > max_height)max_height = h;
});
$(this).css(‘height’,max_height+’px’);
}
})(jQuery);

… And you use it like this:

$(‘div.column’).equalHeight();