Category: Blog

Rails model without corresponding database tables

Lately, I’ve been fortunate enough to contribute to Dot429. It is, among other things, a great place for the LGBT community and their supporters to connect, discuss business and mentor each other.

One of the mini-projects, a contest, required us to ask for a telephone number, but in three separate fields: (area-code), (first three digits), (last four digits). Once the fields were accepted and validated, they were to be concatenated and stored in the database.

Rails makes this very easy: just add the accessors for non-database fields and validate them as we normally would through the built in validators:

  attr_accessor :phone_area, :phone_part_one, :phone_part_two
  attr_accessible :phone_area, :phone_part_one, :phone_part_two
  validates_presence_of :phone_area, :phone_part_one, :phone_part_two, :message => 'Please provide your phone number.'
  validates_format_of :phone_area, :with => /^[0-9]{3}$/, :message => 'Please enter the phone number in Digits 0 - 9'
  validates_format_of :phone_part_one, :with => /^[0-9]{3}$/, :message => 'Please enter the phone number in Digits 0 - 9'
  validates_format_of :phone_part_two, :with => /^[0-9]{4}$/, :message => 'Please enter the phone number in Digits 0 - 9'

When the save() function is called in the controller, the model should validate just fine, even if the particular fields do not correspond to columns in the database.

Now, what if we want to make use of validators for a model that has no table in the database?
Rails throws its arms in the air if you do the above but for a model that has no corresponding database table. The solution is simple: create a dummy table. This, in my opinion, is the simplest solution to the problem because it makes Rails happy. We can even create one dummy talble and associate it to any model that does not have a corresponding database table. Like so:

class Contact < ActiveRecord::Base
  set_table_name :the_empty
  attr_accessor :phone_area, :phone_part_one, :phone_part_two
  attr_accessible :phone_area, :phone_part_one, :phone_part_two
  validates_presence_of :phone_area, :phone_part_one, :phone_part_two, :message => 'Please provide your phone number.'
  validates_format_of :phone_area, :with => /^[0-9]{3}$/, :message => 'Please enter the phone number in Digits 0 - 9'
  validates_format_of :phone_part_one, :with => /^[0-9]{3}$/, :message => 'Please enter the phone number in Digits 0 - 9'
  validates_format_of :phone_part_two, :with => /^[0-9]{4}$/, :message => 'Please enter the phone number in Digits 0 - 9'
end

The first line in our model’s declaration attaches the model with our dummy table. Now we have all the advantages of a regular rails model, without the need to store it.

Here’s the rest of the code from the test project that I created:

# Routes
ActionController::Routing::Routes.draw do |map|
  map.resources :contacts, :member => { :new => :get, :create => :post }
end

# Migration
class CreateContacts < ActiveRecord::Migration
  def self.up
    create_table :the_empty do |t|
    end
  end

  def self.down
    drop_table :the_empty
  end
end

# Contact Controller
class ContactsController < ApplicationController
  def new
    @contact = Contact.new(params[:contact])
    @message = params[:message]
    respond_to do |format|
      format.html
    end
  end

  def create
    @contact = Contact.new(params[:contact])    
    respond_to do |format|
      if @contact.valid?
        phone = "You entered: (#{@contact.phone_area}) #{@contact.phone_part_one} - #{@contact.phone_part_two}"
        format.html { redirect_to :action => :new, :params => {:message => "#{phone}"} }
      else
        message = "Error: #{flash[:error] = @contact.errors.first[1]}"
        format.html { redirect_to :action => :new, :params => {:message => "#{message}"} }
      end
    end
  end
end

<!-- Contact Form -->
<% form_for :contact, :url => contacts_path do |f| %>
  <% if @message %>
  <div><%=@message%></div>
  <% end %>
  <span id="phone_help_text">Phone Number:</span>
  <%= f.text_field :phone_area, :minlength => 3, :maxlength => 3, :tabindex => 6 %>
  <%= f.text_field :phone_part_one, :minlength => 3, :maxlength => 3, :tabindex => 7 %>
  <%= f.text_field :phone_part_two, :minlength => 4, :maxlength => 4, :tabindex => 8 %>
  <%= f.submit %>
<% end %>

Use OSX as an alarm clock with iTunes, AppleScript, iCal or crontab and Energy Saver

Update: Follow this tutorial for Spotify, instead of iTunes

What if none of the alarm clock apps for OSX work just the way we want them? My favorite app until a couple of hours ago was Robbie Hanson’s excellent Alarm Clock 2 app to wake me up. It is simple, intuitive and did exactly what I needed, which was to let me pick a song from my iTunes and set it as my repeating alarm. But then it couldn’t play Soma.fm streams, which iTunes gladly plays.

Luckily OSX comes with excellent built-in tools to make it play the awesome internet radio at 10am.
Here are the steps:

  1. First, create a playlist using iTunes and add music to it.
  2. Now, lets tell our Mac what we want it to do: Open AppleScript Editor. It should open a new script editor window. Paste the following code – be sure to replace MY_PLAYLIST with the name of our iTunes playlist.
    set volume 10
    tell application "iTunes"
    	set the sound volume to 0
    	play user playlist "MY_PLAYLIST"
    	repeat 10 times
    		if sound volume is less than 100 then
    			set sound volume to (sound volume + 10)
    			delay 3
    		end if
    	end repeat
    end tell
    

    The AppleScript is very easy to read. We first set the computer’s volume to full, then start iTunes and tell it to set the volume to 0. Then we tell it to play a playlist. Finally, we gradually increase the volume.
    Go ahead and press the “Compile” button, and then the “Run” button to test out the script. iTunes should fire up and start playing the desired playlist.
    . Now save the script to an appropriate location – I put mine in my home directory (/Users/Cabanaman/) and called it alarm_clock. AppleScript will save it with a .scpt extension, so it might look like alarm_clock.scpt, depending on our display settings.

  3. We now need to do two things: First, we must schedule a time for our alarm_clock script to run everyday at our chosen time, and then we need to make sure that our computer starts up on time for the script to actually run on time! Lets tackle the scheduling first.
  4. We have two choices for this step: the easy way using iCal that Joachim suggested, or the crontab way, which involves some Unix magic!
  5. The iCal way
    Simply, open iCal and create an event. Set the event to start at our preferred wake-up time (10am), and set the alarm to Run Script and select our AppleScript (in my case, alarm_clock). Thats it! Lets skip the crontab, and move onto the final step.
  6. Alternatively, the crontab way:
    We are going to use crontab to schedule our alarm clock. Open up Terminal. What we are going to do now is open up the scheduler file in a text editor, and enter a line for our alarm clock to run at the appropriate time. Here is what the crontab line’s format is:

    MM HH dd mm ww osascript /Path/to/alarm clock script.scpt

    Here MM stands for Minte, HH, stands for hour, dd for day of month, mm for month and ww for day of week. osascript is a program that lets us run AppleScript files from the command line. And finally we will want to enter the path to our alarm clock script. Start crontab’s editor:

    crontab -e

    If we have never done this before, then we are most likely in the vi editor. By default, the vi editor does not let us enter text. Press i to enter insert-mode. Now lets start typing in our crontab entry. Here’s what mine looks like:

    00 10 * * * osascript /Users/eyce/alarm_clock.scpt

    Thats right. I plan to wake up at 10:00am every day! The *’s represent wild-card entries meaning every day / month / day of the week.
    Now, when we’re happy with the line, press Escape to get out of insert-mode, and then type in :wq and press enter. This will save the crontab settings and quit the editor. Lets type in crontab -l and press Enter and crontab should show us our new settings.
    We are done in Terminal and can type in exit and press Enter to end the Terminal session and finally quit the Terminal.

  7. For the last step, we are ready to tell our system to wake up at the right time for our crontab or iCal event to run our AppleScript to run iTunes at the right time! Lets go into System Preferences, then Energy Saver. Lets press the Schedule button and set the wake-up time to about 5 minutes before our actual alarm is supposed to go off. In my case, since my alarm is set for 10am, I set the scheduler to turn my macbook on at 9:55am.

And that is all! =). The computer should start up, along with the cron/iCal event, and then the AppleScript, which will start iTunes with our favorite playlist at 10am! Or, whatever time you set yours for 😉

DIY Rescue-Time, or how I keep myself from wasting time on websites, when I’d rather be working.

About a year ago, I realized that I had a developed a terrible habit. Whenever I was idle, even for a brief moment, I unconsciously visited my favorite news sites. A new browser tab would open, and my fingers would type away. After spending half an hour, an hour, sometimes even a couple of hours on the sites, I’d snap back to realize that I was wasting time. This happened several times every day – I often visited the same site only to discover that I had already read every article of interest.

My solution was to block off any website that I found was too distracting. I wrote the following script and stuck it in my home directory:

#!/bin/bash
if [ "$1" = "free" ]; then
	echo 'Freeing hosts...'
	sudo cp /etc/free_hosts /etc/hosts
	echo '[Done]'
elif [ "$1" = "block" ]; then
	echo 'Blocking hosts...'
	sudo cp /etc/blocked_hosts /etc/hosts
	echo '[Done]'
else
	echo "You can either free or block hosts"
	echo "Usage: "
	echo "	\$switch_hosts free"
	echo "	\$switch_hosts block"
fi

The idea was to replace the host file /etc/hosts with one with a list of blocked websites.
I created two copies of /etc/hosts. One was called /etc/free_hosts and the other was called /etc/blocked_hosts. I then changed /etc/blocked_hosts to look like this:

127.0.0.1	localhost
127.0.0.1	www.reddit.com reddit.com
255.255.255.255	broadcasthost
::1             localhost 
fe80::1%lo0	localhost

Any websites that I did not wish to visit when I was working would simply be redirected to 127.0.0.1. I replaced the default apache homepage on my laptop with a gentle reminder that I had a lot to get done before reading the news.

When I was ready to do work, I opened up a terminal window and typed in:

~/switch_hosts block

Two things happened as a result of this script: suffering from withdrawal, and increased productivity. Initially I tried to visit the blocked sites with even greater frequency than before, only to be presented with my own “get back to work” page. Despite this, I achieved hours more productivity everyday. And after a few days, my frequency attempted site-visits started to go down. I began to concentrate on work for longer stretches of time.

Sometimes it is good to get a small dose of TV, I mean Reddit =)..

~/switch_hosts free

Ubuntu 10.04 with Nginx, Ruby and PHP/PHP-FPM installation: errors and fixes.

A few days ago, I signed up for a Linode instance with Ubuntu 10.04 installed on it. The plan is to gradually move all my websites, including this blog to the new instance. I gave NGiNX a shot as my web server after reading a few articles on how it is light and fast, compared to Apache. Here’s what happened.

1. Don’t lock yourself out of your own server:
The server needs to run NGiNX with Ruby on Rails, MySQL, and PHP. I found Chris Kemson’s guide to be the best and started following it.
The installation was fairly smooth, except for one hilarious mistake on my part: I followed the instructions too closely. During the step for installing UFW (Uncomplicated Firewall), Chris asks us to first enable the firewall, and then turn on support for ssh and http. So I went along and turned on the firewall, only to find myself logged out of the ssh session and no way to go back in. First, I laughed pretty hard at myself, and then logged into the Linode control panel to see if there was anything I could do. Thankfully, Linode provides a web-console, which let me log in and allow ssh access through the firewall.

2. Phusion Passenger only speaks in one Ruby at a time
Something I wanted to support was being able to run both Rails 2 and 3. A lot of people seem to recommend installing RVM for this. RVM lets us run multiple versions of ruby on the same system, and switch between them as needed. This means that it is possible to setup Rails 2 under Ruby 1.8.7 and Rails 3 under Ruby 1.9.2. So far so good. The problem is in deployment. You see, Phusion Passenger does not allow us to run multiple versions of Ruby. The line
export PATH=/opt/myruby/bin:$PATH is an http level statement in nginx.conf, and specifying a different ruby for each server simply generates an error. I eventually settled with removing RVM, and running Rails 2 and 3, installed under the same Ruby version (1.9.2).

3. Errors with hard to find solutions
Here are a few NGiNX configuration related errors that haunted me:

  • 403: Forbidden / 500: Internal Server error / Completely blank index page.
  • Going to index.php (the root url) initiates a download of the index.php file

The following fixes seem to work for the above cases:

  • I like to serve my website out of each user’s public_html directory. Make sure that the public_html directory has the proper permissions to allow NGiNX to access it.
  • Make sure that the index setting specifies index.php:
    index index.html index.htm index.php;
  • Make sure that your server has the following lines:
        location ~ \.php$ {
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            include        fastcgi_params;
        }
    
  • If you are deploying a rails website, then set the root in your site’s nginx configuration to that Rails project’s public folder, and not your website’s base public_html folder

Here’s what my NGiNX configuration looks like:

worker_processes  1;
events {
    worker_connections  1024;
} 
http {
    passenger_root /usr/local/lib/ruby/gems/1.9.1/gems/passenger-3.0.7;
    passenger_ruby /usr/local/bin/ruby;
    rails_env production;
    include       mime.types;
    default_type  application/octet-stream;
    index index.html index.htm index.php;
    sendfile        on;
    keepalive_timeout  65;
    server {      
        listen       80;
        server_name  localhost;
        location / {
            root   html;
        }
    }
    include sites-enabled/*;
}

And my site-specific configuration, for jaripeo.com, which runs on Rails 2:

server {
    access_log  /home/jaripeo/access.log;
    error_log  /home/jaripeo/error.log;
    listen  80;
    server_name  jaripeo.com *.jaripeo.com;
    root /home/jaripeo/rails/current/public;

    location ~ \.php$ {
        fastcgi_pass   127.0.0.1:9000;
        fastcgi_index  index.php;
        include        fastcgi_params;
    }
    passenger_enabled on;
}

How to give a WordPress Page a memorable address using Apache’s RewriteRules

Alright so this is pretty awesome:

Background:
We have just created one or two new WordPress pages using wp-admin – say an “About” page and a “Resume” page. You’ve done all the work to write up all the content, and format it properly and when you publish, the pages look fantastic!

Problem:
The About and Resume pages have web addresses that look like this: http://www.cabanalabs.com?page_id=99
This is all well and good, but no one is going to remember that our resume is sitting at page_id=99. It would be much more desirable if someone could just type in: http://www.cabanalabs.com/resume

A simple solution, if you are running a newer version of Apache as your web server:
Assuming that we have administrative access to our apache server, and know where our VirtualHost file is, possibly in the /etc/apache2/sites-available/ directory. If you don’t – then stop right here and get a hold of your system administrator! He may have a better solution to this than what you see here :-)..

Modify the VirtualHost for our blog’s domain so that it would include a RewriteRule that would allow someone to then go to the simpler address, http://www.seevishal.com/resume, and reroute them to the correct WordPress page, which in this case would be http://www.seevishal.com?page_id99.

Here’s what the VirtualHost file for seevishal.com looks like:

        ServerName www.cabanalabs.com
        ServerAlias cabanalabs.com *.cabanalabs.com
        DocumentRoot /home/cabanalabs/public_html/
        ErrorLog /var/log/apache2/error.log
        LogLevel warn
        CustomLog /var/log/apache2/access.log combined
        ServerSignature On
        RewriteEngine on
        RewriteRule ^/resume(.*) http://www.cabanalabs.com?page_id=99$1 [L]
        RewriteRule ^/about(.*) http://www.cabanalabs.com?page_id=116$1 [L]

As you can see, we’ve added three lines towards the bottom. One to turn on the functionality, and two with the RewriteRule settings.

For more reading and examples on how to use RewriteRules, check out
Apache’s Mod Rewrite guide

1 2