helion-prime
home about us blogs contacts

Archive for the ‘web-development’ Category

Log rotation in Ruby on Rails applications

Thursday, November 19th, 2009

preamble

Even on mid-size applications logs grow enormously fast, it’s a pity Rails doesn’t provide built-in functionality for that like Apache web-server does. Fortunately there is an easy and fast solution for that issue.

1. Install cronolog

“cronolog [http://cronolog.org/] is a simple filter program that reads log file entries from standard input and writes each entry to the output file specified by a filename template and the current date and time.”

For details, and list of parameters see: [http://cronolog.org/usage.html]

On GNU/Linux Debian:

# apt-get install cronolog

2. Setup your Rails application

Edit necessary environment file: like ‘config/environments/production.rb’ file

1
2
3
4
5
# system logger configuration
# config.logger = SyslogLogger.new

config.logger = Logger.new(IO.popen("FULL_PATH_TO_CRONOLOG log/production.log.%Y%m%d", "w"))
config.logger.level = Logger::INFO

That’s all, fast and easy .. Enjoy!

Easy image scaling for RoR developers

Monday, November 2nd, 2009

We have common task: image scaling [http://en.wikipedia.org/wiki/Image_scaling], and correct understanding that: we can’t ask users to provide image of appropriate sizes, just use width and height CSS parameters for images, and thumbnail is always required feature.

Luckily we have ImageMagic library [http://www.imagemagick.org] and program interfaces for popular languages.

install RMagic gem
# gem install rmagick

add small code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
require 'rubygems'
require 'RMagick'

class ImageController < ApplicationController

def index

  # determine basic params
  w = params[:w]
  h = params[:h]
  path = params[:path]

  if !w.to_s.empty? && !h.to_s.empty? && File.exists?(path)
      begin
        image = Magick::Image.read(path).first
        transformed_image = image.resize_to_fill(w.to_i, h.to_i)

        # send image
        send_data(transformed_image.to_blob, :disposition => 'inline',
         :type => "image/#{image.format.downcase}")

      rescue Exception => e
        Rails.logger.error e.message
        Rails.logger.error e.backtrace.join("\n")
        render :text => "Error processing image #{type}/#{aliaz}", :code => 404, :layout => false
      end

  end

end

Here to re-size images we use ‘resize_to_fill’ ImageMagic method:
re-size the image to fit within the specified dimensions while retaining the aspect ratio of the original image, and if necessary, crop the image in the larger dimension.

Sure you understand that resizing takes time and so you should cache re-sized images.

For additional info look thru:
[http://studio.imagemagick.org/RMagick/doc/]

Multi-domain applications in Ruby on Rails

Thursday, September 3rd, 2009

preamble

Ruby on Rails is a great framework that still luck some common features, among them: multi-domain support.
Here I will describe fast solution that doesn’t work for every browser and another one that do the work.

Ok, you did your homework and google something like ‘ruby on rails multi-domain’.
Very often provided solution:

edit environment.rb

1
config.action_controller.session = {:domain => '.mydomain.com'}

With that parameter Rails always read cookies from same domain. In real some browsers forbid for applications to read cookies from other domain due to insecurity of that operation. And as Mozilla Firefox in set of browsers that forbid that we just need another solution.

Now it’s clear that we should implement necessary functionality other way.

Here we go:

1. will store session ID in the database(by default Rails2 store it in cookies)

environment.rb:

1
config.action_controller.session_store = :active_record_store

and then execute rake task that create necessary DB migration:

1
rake db:sessions:create

Apply it with: rake db:migrate.

2. setup session parameters

environment.rb:

1
2
3
4
5
6
7
8
9
require "rubygems"
require "active_support"

config.action_controller.session = {
   :session_key => '_myapp_session_id',    # session identification key
   :secret      => '89sHslddfsd98klasdKd', # hash code of session generator(make it random and longer)
   :cookie_only => false,
   :expire_after => 1.week,                # TTL (time to live)
}

3. let’s create session creation handler

application_controller.rb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
before_filter { |controller|
   opts = controller.request.session_options
   key = opts[:key]

   # use session ID if it's passed
   if controller.params[key]       
      # session initialization with old ID
      controller.session[:nothing]

      opts[:id] = controller.params[key]
      controller.request.session_options = opts
     
      # session initialization with new ID
      controller.session[:nothing]
   end
}

4. session pass

We need to pass session ID as parameter when user change domain name, and within domain we still use cookie.

1
“#{request.session_options[:key]}” => request.session_options[:id]

It’s wise to use session initialization before request.session_options[:id] invocation due to Rails use lazy loading, and session can be uninitialized.
Use something like: session[:nothing].

Pay attention that information that Rails get from cookie has bigger priority, and so if you have some parameter in cookie Rails will use it firstly.

Note:
An attacker can still steal you session ID by sniffing the network, or exploiting javascript, he/she gets the value from the cookie itself. If you care about security so much just use HTTPS.

Fast scalability of Ruby on Rails with mongrel under OpenBSD

Wednesday, August 12th, 2009

preamble

Everybody who works with ruby on rails more then month knows at least 2 things:
it’s great framework, but can’t handle multiple requests simultaneously due to it still doesn’t use threads.

fast start

As scalability is common issue, rubyonrails site wiki provides full set of solutions:
[http://wiki.rubyonrails.org/#deployment_stacks]

But we as fast solution will use great OpenBSD pf (Packet Filter) that capable to do many cool things.

First issue is standard mongrail cluster that can start several instances of mongrail can only create them on one IP with different ports,
and pf can’t distribute requests among different ports on same IP.

Here we can create 2 simple scripts that start and destroy server instances:
# cat start.sh

1
2
3
4
5
6
7
8
9
10
count=1
for ip in 10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4 10.0.0.5
do
mongrel_rails start -e production -d --user myapp --group myapp --chdir /var/www/railsdocs/myapp \
--address ${ip} \
--pid /var/www/railsdocs/myapp/tmp/pids/mongrel.${count}.pid \
--log /var/www/railsdocs/myapp/log/mongrel.${count}.log

count=$(($count + 1))
done

# cat stop.sh

1
2
3
4
5
for instance in {1..5}
do
mongrel_rails stop --wait 3 --chdir /var/www/railsdocs/myapp \
--pid /var/www/railsdocs/myapp/tmp/pids/mongrel.${instance}.pid
end

And we need to enable pf:
#/etc/rc.conf.local

1
2
pf=YES
#pflogd_flags=                   # add more flags, ie. "-s 256"

add one string to configuration file for load distribution:
#/etc/pf.conf

1
2
rdr pass log on re0 proto tcp from any to SOME_IP port 80 ->
{10.0.0.1, 10.0.0.2, 10.0.0.3, 10.0.0.4, 10.0.0.5 } port 3000 round-robin

check work with:
# pfctl -s nat

monitor with:
tcpdump -n -e -ttt -i pflog0

for more info on pf:
http://www.openbsd.org/faq/pf/
man pf.conf (especially ‘TRANSLATION’ and ‘POOL OPTIONS’ sections)

Then when you see you need more advanced solution for load distribution you can install haproxy.
Check it with [http://www.openbsd.org/4.5_packages/i386/haproxy-1.3.15.7.tgz-long.html]

Twitter directory: our look on how it should work

Monday, July 6th, 2009

“Be the change you want to see in the world.”
Mahatma Gandhi, Indian political and spiritual leader (1869 – 1948)

There are a lot of twitter directories on Internet today. Here I would want to check few most popular ones and provide our look on good directory.

Structure of directory

1. plain list of categories
There is a number of categories on top page, user select one category, and browse all members in that category.

justtweetit
example from: [http://justtweetit.com/]

disadvantages:
a. enormous list of categories on main page.
b. cutting the list of categories creates too broad categories where too many entries are placed.

2. tags for naming of entries
For every entry user can provide number of tags, then users can select appropriate tag.
In theory user has ability to select most narrow meaning and thereby limit number of entries.

wefollow
example from: [http://wefollow.com/twitter/tags/]

disadvantages:
a. there are still too broad tags like ‘celebrity’ with enormous amount of entries.
b. number of tags, so it is hard for user to select most narrow tag.

3. search engine style
Like in search engine user provides search term, and system search for similar entries.

twitdir
example from: [http://twitdir.com/]

disadvantages:
a. user should know twitter name.
And if so user can use build-in twitter search [http://search.twitter.com]. But what if he/she wants to find for example pop style singer? Then user needs directory again!

Administration of directory

All current directories provide possibility to any user to add himself/herself and so suffer from spammers and common(uninterested) users. There should be some quality criteria and some administrators that ensure continues quality of twitter IDs and correctness of provided information.

As it is money consuming tactic directory should make some money to cover costs or use open-source model where authorized users can check entities as it works in DMOZ directory [http://www.dmoz.org/help/become.html]

Will follow Gandhi’s idea

After some discussions within our company we have decided finally to create our own directory of twitter users.
We are taking into account disadvantages of current directories, and so our directory:
*has tree structure to reduce complexity, and size of categories
*uses moderators that ensure quality of twitter IDs before they add them.

Start exploration at: [http://twitwho.net].

Of course there is unlimited ways to improve everything, and so we are open to any suggestions and complains:
helion-prime’s twitter: [http://twitter.com/helionprime]
twitwhohq’s twitter: [http://twitter.com/twitwhohq]

©2010 Helion-Prime Solutions Ltd.
Custom Software Development Agile Company.