Thursday, 16 October 2008

Creating a summary

I have an app that has rows of statistics. We wanted to create summaries of arbitrary rows.
This method seems to work:

  def self.create_summary_row(array)
unless array.blank?
klazz = array.first.class
sum_stat = klazz.new
array.each do |line|
if line.is_a?(klazz)
line.attributes.each do |k,v|
unless v.nil? || v.is_a?(Time) || v.is_a?(Date)
if sum_stat[k].nil?
sum_stat[k] = v
else
sum_stat[k] += v
end
end
end
end
end
sum_stat
end
end

Monday, 29 September 2008

ec2onrails

This is so great - goodbye other hosting companies that can't compete!

Amazon has hosting facilities known as ec2 (elastic compute cloud). You pay by the hour ($.10 for a small installation). That works out to around $70/month. But, the power you get is much better than your average hosting.

Paul Dowman has released a great ec2 instance called ec2onrails that can get your rails app up and running on ec2 in about 30 minutes. I am now using it for FilmAmora as well as for another client.

It is awesome!

One thing I discovered today was the sweet built-in support for cron jobs. Write a script and plop it in your app's script directory. Call it hourly, daily or weekly (perhaps monthly? I didn't check). This script will get run automatically by an already existing cron job! No need to figure out those silly cron settings. Very cool!

I highly recommend it. FilmAmora is running much much better on it than on the old hosting (where I had to restart it every day just to hopefully have enough memory to run 2 mongrels).

Friday, 15 August 2008

secure forms

One thing I struggled with in RoR was creating forms that submitted to https. So I ended up writing a couple of helpers:

  def secure_form_for(record_or_name_or_array, *args, &proc)
unless RAILS_ENV == 'production'
url_options = {}
else
url_options = {:protocol => 'https://', :only_path => false }
end

options = args.last.is_a?(Hash) ? args.pop : {}
if !options[:url].nil?
options[:url] = url_options.merge options[:url]
else
options[:url] = url_options
end

return form_for(record_or_name_or_array, options, &proc)
end


and

  def secure_form_tag(*args, &proc)
logger.debug("secure_form_tag args #{args.inspect}")
unless RAILS_ENV == 'production'
url_options = {}
else
url_options = {:protocol => 'https://', :only_path => false }
end

options = args.last.is_a?(Hash) ? args.pop : {}
if !options[:url].nil?
options[:url] = url_options.merge options[:url]
else
options[:url] = url_options
end

logger.debug("secure_form_tag options #{options.inspect}")

return form_tag(options, &proc)
end


The should be simple replacements for form_for and form_tag. Now, I have to admit I wrote these when I was using Rails 1.2.5, so there might be some things in 2.x that make these redundant, but, they work for me.
The only caveat is that if you are doing a form where you are not passing in the action, just the object e.g

<% form_for @object do %>


Then you are going to have to supply the actions. I am looking into this now, and I might rewrite this post if I sort it out!

Saturday, 26 July 2008

xml_hidden plugin

Recently I've been investigating the steps needed to open up FilmAmora's API to the outside world. That means supplying xml data so people can do what they want with it.
But I didn't want sensitive data in models to be exposed in the xml. And I also am too lazy to write custom to_xml methods for everything.

So I wrote a plugin call xml_hidden That lets you set something on the class to hide certain attributes from xml output.

class Film < ActiveRecord::Base
attr_xml_hidden :acquiring_url, :id, :created_at
end


Now whenever I output a film to xml those values can't be seen.

Sunday, 20 July 2008

Escaping for JavaScript

Recently I've started to use the most excellent Prototip2 for doing sexy tooltip stuff. It works a treat.
The only problem I have had is that some of the things I want to put into the tips have single quotes in them (e.g Bob's Team). I was surprised to find that Rails doesn't (as far as I could find) have a handy dandy way of making strings JS friendly. So I whipped up this extention to Erb::Util.
I hope some of you find it useful. It will escape single quotes and as an added bonus it also does the html escaping so you only have to make one call.

class ERB
module Util
def js_escape(str)
h(str.gsub(/[']/, '\\\\\''))
end

alias js js_escape
module_function :js
module_function :js_escape
end
end


I put this into an initializer.

You can then call it from your views like this:

<%=js team.name%>

Monday, 14 July 2008

Combating XSS

This info is available elsewhere, but as I always forget, this is a good place to repeat it.

Install the White List plugin. Get it here

Once installed you'll need to add the following line to the init.rb of the white_list plugin:
ActionView::Base.send :include, WhiteListHelper


In the Application.rb (Application Controller)
include HtmlFilterHelper
before_filter :sanitize_params


Then I have a class called HtmlFilterHelper
module HtmlFilterHelper
def sanitize_params(params = params)
params = walk_hash(params) if params
end

private
def walk_hash(hash)
hash.keys.each do |key|
if hash[key].is_a? String
hash[key] = white_list(hash[key])
elsif hash[key].is_a? Hash
hash[key] = walk_hash(hash[key])
elsif hash[key].is_a? Array
hash[key] = walk_array(hash[key])
end
end
hash
end

def walk_array(array)
array.each_with_index do |el,i|
if el.is_a? String
array[i] = white_list(el)
elsif el.is_a? Hash
array[i] = walk_hash(el)
elsif el.is_a? Array
array[i] = walk_array(el)
end
end
array
end
end


For what it is worth, I also do stuff like this:

<%=white_list synopsis.synopsis[0,100].gsub(/<\/?[^>]*>/, "")%>


Which removes any html-style tags from the text and then white_list's it before outputting.

Wednesday, 9 July 2008

Becoming a Git

Recently the SVN repository service we were using for FilmAmora had a lengthy outage. So, being a real Rails-er I decided to switch over to GitHub. Getting the source up into it was pretty easy.

So, I went ahead and started making changes and doing git commit's and all that good stuff. Well, today I went to the projects homepage on GitHub and you can imagine my surprise and horror when I saw that it looked like nothing had been checked in since my original commit.

Wot de hell?!

I then scoured the net for Git for dummies without success. So here it is:

1) Do all the stuff they tell you do to to get your code in.
2) Do your commits... but remember that for some strange reason you are committing into your LOCAL Git repository.
3) here's the key - do a git push! that will chuck your code up onto the server.

Seems perhaps obviously, but coming from an svn or cvs background it confused the hell out of me.
At a later date (probably this weekend) I will write a little Git note about how this works from the perspective of someone used to using one of the more traditional source code systems.