Archive for the 'ruby' Category

Rails 2.0 on Ubuntu Gutsy

Thursday, April 3rd, 2008

I must confess that Rails makes me feel stupid every time I use it. The accepted truism about the framework is that it boosts your productivity like no other. Unfortunately people forget to tell you that there is second part to this statement that goes something like this: “once you learn to think the Rails way”. It really forces a certain mindset upon you, and deviating from it means that you are actually working against the framework, rather than having it do the work for you. It takes a little while to get used to it, and there are moments when you have a great scaffold thing going on with bunch of interacting tables/entities, but you sit there for 20 minutes trying to figure out how to make a simple pull down menu (aka select statement) which would let you choose the foreign key from the other table. You could do it the hard way, but it turns out that it is astonishingly simple:

<%= collection_select :foo, :bar_id, bar.find(:all), :id, :bar_name %>

This will create a select statement looking something like this:

<select name="foo[bar_id]">
    <option value="1" selected="selected">Bar 1</option>
    <option value="2">Bar 2</option>
    <option value="3">Bar 3</option>
</select>

It really took me some digging to figure that out - mainly to realize that what I needed was in a ActionView::Helpers::FormOptionsHelper class. A lot of the online tutorials simply gloss over little details like that - for example, the importance of helpers, which I now know are pretty damn convenient.

Then there is that whole Rails 2.x vs. Rails 1.x debacle. The two are not entirely compatibile, and there are significant differences in the way they work. Needless to say, when version 2.0 instantly invalidated every single Rails book on the market by removing the active scaffolding which everyone was using in the initial examples. I already got burned on it once, and now I was hit with it again, only from the other side. When I decided to install rails on Gutsy, I did what any reasonable Ubuntu would do:

sudo aptitude install ruby rails mongrel

Few minutes later I was all set up and ready to go. Or was I? I gently issued a command like this:

script/generate scaffold Foobar foo:string bar:string

I got hit by some cryptic error about unknown string identifier or something among those lines. WTF? It took me few minutes of useless googling, and cursing to realize I simply had the old version of rails installed. I could have went along and simply use the nice active scaffolding for my project, but I figured if I am to learn this damn framework, I should probably use the latest and the greatest version. How to install it on Gutsy though? The answer is - via gems.

First, get rid of the 1.x rails installation if you actually have it on your system:

sudo aptitude remove rails

Next, install the new rails:

sudo gem install rails --include-dependencies

That should do it. I think it’s possible to downgrade back to 1.x if you remove rails via gem and then install it back via apt bur I haven’t tried it.

Also, small caveat - you may or may not need to update your gems package to do that. You can do it by issuing a command:

sudo gem update --system

Be warned that it will actually break the gem command itself. If you try running it, you will get the following error:

/usr/bin/gem:23: uninitialized constant Gem::GemRunner (NameError)

Why is this? Take a look at this:

$ ls -l /usr/bin/ | grep gem
-rwxr-xr-x  1 root   root        701 2007-08-24 01:18 gem
-rwxr-xr-x  1 root   root        785 2008-04-01 11:25 gem1.8
-rwxr-xr-x  1 root   root       3201 2007-08-24 01:18 gemlock
-rwxr-xr-x  1 root   root       1778 2007-08-24 01:18 gem_mirror
-rwxr-xr-x  1 root   root        515 2007-08-24 01:18 gemri
-rwxr-xr-x  1 root   root         70 2007-08-24 01:18 gem_server
-rwxr-xr-x  1 root   root       1813 2007-08-24 01:18 gemwhich
-rwxr-xr-x  1 root   root       7947 2007-08-24 01:18 index_gem_repository

Apparently all the gem_* commands have been deprecated in the 1.x releases of rubygems. The version in gutsy repo is 0.9.4 which means it still uses them. The update command brings you to 1.1.0 release but unfortunately does not remove the old scripts from /usr/bin. So the original gem and gem_ commands are useless. Quick workaround here is:

sudo mv /usr/bin/gem /usr/bin/gem.old
sudo ln -s /usr/bin/gem1.8 /usr/bin/gem

You could probably remove the gem binary, but I simply renamed it, and then created a link to gem1.8 in it’s place. It works well enough, and if you need to do a downgrade later on, all the files are still intact.

Starting a Rails 2.0 Project

Thursday, January 17th, 2008

Since Rails 2.0 fucked up just about every single online tutorial out there by removing the scaffold method, I decided to document a step by step process of starting a brand new project. I think it’s important because the approach changes. In the past you could start from designing database, and then work your way from there. This is no longer the case.

I’m using SITS as an example here. What is SITS? As far as you are concerned it is my little vaporware project that exist only in my feeble mind, and as a empty google code page. Oh, and it also exists as part of the monstrous 45,000 line php craziness I maintain at work. It used to be an individual PHP project at one point, then it got swallowed by the all purpose evaluation and report tracking monster and extracting it from there proved to amount almost to a total rewrite. I figured - why not use Rails and learn something along the way?

So let’s get started. First thing we want to do is to actually create a project. I’m assuming you have Ruby, Rails and MySQL installed. Don’t touch the database yet. Btw, I’m using windows because I don’t feel like switching machines for this - sue me.

Go go gadget RAILS:

C:\projects>rails sits
      create
      create  app/controllers
      create  app/helpers
      create  app/models
      create  app/views/layouts
      create  config/environments
      create  config/initializers
      create  db
      create  doc
      create  lib
 
      --- snip ---
 
      create  log/server.log
      create  log/production.log
      create  log/development.log
      create  log/test.log

It’s a whole lot of output so I snipped it. You will also note I’m using C:\projects as my directory. This is actually a junction that points somewhere else, but you don’t need to worry about this. I just got annoyed that the paths were so long they were causing my code box scroll sideways so I C:\projects to my real projects folder.

Anyways, on to configuration. \project\sits\database.yml is the database config file - and practically the only config file we will need to write for this project. I have set it up like so:

development:
  adapter: mysql
  database: sits_dev
  username: root
  password: [passwd]
 
test:
  adapter: mysql
  database: sits_test
  username: root
  password: [passwd]
 
production:
  adapter: mysql
  database: sits_prod
  username: root
  password: [passwd]

I’m using the root account right now because we will be using built in rails magic to add and drop tables and do all kinds of other fun things. Once the project is ready for production, I will probably go back and change this to a locked down user which only has select, update and delete privileges for the tables it needs. As a side note, when you edit this file make sure that the config lines for each environment are indented exactly two spaces. No more no less. I mean, unless you enjoy cryptic errors - cause you gonna get plenty if you fuck up the layout. It’s kinda like in python, but only for this file. Ruby itself doesn’t really care about indentation that much.

Let’s create the 3 databases:

C:\projects>rake db:create:all

Yup, rake is like fucking magic - you don’t even need to touch MySQL tools. I touched them though to verify the databases were created:

Databases Created by Rake

We have the databases now, now it’s time for scaffolding. What about models, you ask? What about controllers? Scaffolding does that for us. The bad part is that we need to roughly know what do we want to scaffold from the get-go. I kinda know what I’m doing since I did this once already in php and then fucked it up by integrating it into a monster that will one day devour my soul. So have an idea of what we should be designing. I will start with user table because it is stand-alone (ie. it does not belong_to or is not composed_of anything). Our user will have a username, a password (hashed of course), an email (naturally), account creation date and user level. The level will of course be on a scale from luser to admin, and I will use numeric values to represent them. Why? Because I used enums in the past and I ended up with contraptions like lpuser (low priv user), superuser, superadmin, and etc.. Numeric level system is easy to extend.

C:\projects\sits>ruby script\generate scaffold User username:string 
	password:string created_at:datetime level:integer
      exists  app/models/
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/users
      exists  app/views/layouts/
      exists  test/functional/
      exists  test/unit/
      create  app/views/users/index.html.erb
      create  app/views/users/show.html.erb
      create  app/views/users/new.html.erb
      create  app/views/users/edit.html.erb
      create  app/views/layouts/users.html.erb
      create  public/stylesheets/scaffold.css
  dependency  model
      exists    app/models/
      exists    test/unit/
      exists    test/fixtures/
      create    app/models/user.rb
      create    test/unit/user_test.rb
      create    test/fixtures/users.yml
      create    db/migrate
      create    db/migrate/001_create_users.rb
      create  app/controllers/users_controller.rb
      create  test/functional/users_controller_test.rb
      create  app/helpers/users_helper.rb
       route  map.resources :users

Can you see what I’m doing here? I’m specifying the fields and their data types as arguments for the scaffold script. These fields will be included in my views, and I will also get an automagical database migration file. I can go in and edit it adding extra fields that won’t show up in the views if I want to. To do so I just need to open the db\migrations\001_create_users.rb file:

class CreateUsers < ActiveRecord::Migration
 
  def self.up
    create_table :users do |t|
      t.string :username
      t.string :password
      t.datetime :created_at
      t.integer :level
      t.timestamps
    end
  end
 
  def self.down
    drop_table :users
  end
end

Note - I didn’t write that code. Rails did. Neat huh? All I needed to do was to specify bunch of field names and data types. What data types can you use in a migration (or when specifying scaffold)? I think the list is as follows:

Rails Migration Types

List is courtesy of the Rails Migration Cheatsheet. They have an expanded version of this table on their site - I just stole a piece of it for quick reference.

What now? We can use our old friend Mr. Rake:

C:\projects\sits>rake db:migrate
(in C:/projects/sits)
== 1 CreateUsers: migrating ===================================================
-- create_table(:users)
   -> 0.0630s
== 1 CreateUsers: migrated (0.0630s) ==========================================

In effect we should see two new tables in the _dev database like this:

Tables Created by Migration

Just to be sure, let’s look at the schema of the users table to make sure everything is correct:

Users: Database Schema

Yup, everything works! Now let’s launch this shit! I’m using Mongrel instead of WebRick because it is ♪Harder, Better, Faster, Stronger♪. Also it has a picture of a dog on it’s webpage so clearly it must be superior. Not even mentioning the Win32 service support that ma To install mongrel just do:

gem install mongrel

To start it, simply navigate to the project and run:

C:\projects\sits>mongrel_rails start
** Starting Mongrel listening at 0.0.0.0:3000
** Starting Rails with development environment...
** Rails loaded.
** Loading any Rails specific GemPlugins
** Signals ready.  INT => stop (no restart).
** Mongrel 1.1.2 available at 0.0.0.0:3000
** Use CTRL-C to stop.

I actually have no clue why the default mongrel output displays the ip as 0.0.0.0 instead of 127.0.0.1 but I assure you it works. We can test it by simply navigating to http://locahost:3000/Users

Scaffolded Project

All the CRUD actions are supported here so I can easily add a new user by simply hitting a link on the bottom of this page:

Create a New User

I don’t really like the creation date dialog - it probably would be smoother if the date got appended automatically at the moment of creation. But I think this is something I can easily change by editing either controller or the view. As it is right now the password is not getting encrypted so this is another bit that we need to fix But this is pretty much the point of scaffolding - it gives you a starting point, not really a complete solution.

Is this better than the old way? On one hand having the code generated for you is nice. On the other hand the auto-generated code might be a little bit confusing to a newbie. The dynamic scaffold gave you a blank slate you could fill out by coding from scratch. Now we get a pile of cryptic code that needs to be deciphered before we can move on. Perhaps we will learn better this way, but I’m not sure. I kinda like the from-scratch approach. But there is not much I can do about it other than downgrading to a previous version of Rails. P

That’s all I have for today. I mostly just wanted to document all the little things you need to do to start a scaffolded project from scratch. I might post more as I re-write SITS but I guess that really depends on whether or not I run into any interesting problems, or cool Rails thing I want to talk about.

What happened to scaffold in Rails 2.x?

Wednesday, January 16th, 2008

Rant time! This one may or may not ruffle some feathers, but frankly I don’t care. I’m probably late to this party and missed out on all the big flame wars seeing how 2.0 was released at the beginning of December. Still, this kinda pissed me off. I just wanted to ask the Rails team what exactly was so horribly wrong with the scaffold method that they had to rip it out in 2.x release?

Let me back track a second. Some of you probably don’t have a clue of what I’m talking about here so let me paint you a picture here. This is how just about every Rails book and online tutorial starts the same. First thing they teach you is to create a Rails app, create the database and then set up a model and a controller for some database table (let’s call it things).

Then, inside the things_controller.rb file you were supposed to do:

class ThingsController < ApplicationController
  scaffold :thing
end

This would generate an invisible dynamic scaffolding that would take care of basic CRUD operations. The idea was to start clean, and then slowly chip off the scaffolding by overloading it with your own content. For example, once you define index method in the controller, and and index view the listing is no longer handled by the scaffold.

At any point of development process you could have dropped this single line in any of your controllers to get bare-bone basic functionality on the fly. It had that wow factor, that was bringing all the boys to the yard, like the milkshake… Or something like that. My point is was that it was easy to use, did not clutter your codebase with auto-generated gunk and every fucking Rails tutorial on the planet was using it.

Do you know what happens when you try to use the scaffold line in the current 2.0.1 release of Rails? First you get an error message. Then a little guy jumps out of the closet and kicks you in the balls, steals your wallet and then jumps out the window. Or maybe that’s just happened to me. Either way, it’s not a pleasant experience.

At first I thought that maybe I just can’t spell scaffold. But no - it just no longer exists. I actually had to google it cause I had no fucking idea. They just riped it out and junked it. Yay backwards compatibility. I can’t wait to see what useful features you will remove in Rails 3.0 to fuck up my work flow! Wohoo!

I know that scaffolding was just a neat feature which really didn’t influence how a deployed rails application performs or behaves. I know it was not essential, and I know it was only useful in the very early stages of development. Blah, blah, blah. Still, why remove it? The official release post doesn’t even mention this change.

I looked through some mailing lists and forum posts, and I on every single one I saw pompous jackoffasaurs taking turns enlightening masses on how only idiots used scaffold method, that it was abused, that it was a “crutch” and how the new way actually forces retards to look at the code. Really? You are serious?! They removed it out of goodness of their hearts to save us heathens from our wretched scaffolding practices? Thank you there, Dijkstra - why don’t you write me a “considered harmful” essay while you are at it? Geezz…

So I’m asking - why was it removed? Perhaps someone can give me an objective, unbiased and non-elitist analysis on why it was not fit for 2.0. I just want to rationalize this. I want to find some sort of justification. And no, “cause u were doin it rong” just doesn’t cut it for me. Give me a benchmark showing that dynamic scaffolding is slow, tell me about security concerns, about compatibility migration issues. Tell me how how the “new way” improves the work flow, improves coding practices and is generally better. Give me something. I might buy it - who knows. I just couldn’t find any explanation like that anywhere out there. Everyone is simply viciously bashing n00bs and passive-aggressively flogging anyone even daring to ask about the scaffold method. evil

You can naturally still scaffold in 2.x but only via code generation. And when you do it, the script generates everything including the model, controller, views and database migrations. In fact, they dumbed it down to the point where it no longer even looks at database to dynamically detect the correct fields and data types.

The 2.0 way is to scaffold first, then create a database. The script generates a migration based on the list of fields you specify as arguments. Same fields are also used for the views. If you don’t specify any fields on the command line, you will get a half-assed views that do nothing. Nice thing is that if you do specify correct fields on the command line, you end up with a complete set of controllers, views, migrations and etc. All you need to do is to run the migration script, then fire up the server and you are good to go. It does make sense conceptually - after all in real world you put scaffolding up before you start building. Maybe this is a superior approach, but I just don’t see why we can’t have it both ways.

Needless to say, I’m a little bit disappointed with this change. I can only imagine how confusing it must be for new Rails users who are trying to follow a simple tutorial from a book. I was confused as hell for a minute there, and the whole thing left me a bit turned off to rails. It’s a great framework, and I’m still planning to use it on a few projects, but this whole scaffolding debacle really did a great job of dousing and subduing my enthusiasm. Maybe it’s for the better and it will allow me to look at RoR objectively instead of jumping on the “OMG this is FANTASTIC!” bandwagon.

Wantonly breaking backwards compatibility on a whim and without any justification is a cardinal sin of software development and frankly it scares me a bit that they chose to commit it. I’m not saying breaking backwards compatibility it’s always bad. Far from it - sometimes you need to ditch old code if it is holding you back. And that’s perfectly acceptable. But fucking up chapter one of just about every published Rails book, and every single online tutorial in one swooping move is not a good thing.

Since the begging of December people have been reading the now outdated tutorials, and scratching their heads trying to figure out why Rails is not working. It’s a good thing everyone loves Rails these days. I bet most people will forgive and forget, but I think they really shot themselves in the foot with this. P

Aptana - First Impression

Wednesday, June 6th, 2007

Yesterday I spent some time talking to some dudes running a computer security company in NYC. They have used Ruby on Rails for one of their recent projects, and they were raving about it like madmen. I literally couldn’t make them shut up about RoR. Their enthusiasm was actually kindoff contagious, and now more than ever I’m determined to jump into Ruby again.

So I downloaded Aptana (aka former Rad Rails IDE) which is essentially an Eclipse geared for web development. The vanilla version is just a generic web application IDE, but you can download a Rails specific version - or if you already have the vanilla you can install the Rails components via Help→Software Updates.

Eclipse is probably the best Java IDE I have used in my life, so using a similar tool for Rails should really make the learning curve of RoR much smoother. I haven’t played with it much, but it looks awesome. It seemed a tad slow when starting up though - slower than Eclipse. Once the app loaded however it seemed responsive.

When I have a chance to play with it some more, I will post a review.

And yes, if you wondered, this is filler content. I had a writers block (blogger’s block?) for the last few days so I’m trying to ride it out by posting about anything and everything.

Anyways, here are some questions for you :

Developers: Love or hate Eclipse? Discuss!

Web Developers: Do you also have a boner for Ruby on Rails like these dudes from NYC? Or do you think that the framework is way over-hyped?

Bloggers: What do you do when you open up your “Write Post” page, and you can’t think of anything even remotely interesting to write about? How do you deal with writers’ block situations?

Ruby on Rails doesn’t Scale Well

Friday, April 27th, 2007

Ruby is a really great language with some awesome features, and Rails make it even better. But it appears that it does not scale well yet. Twitter is a great example of using RoR to run a website with millions of users hitting your server few hundred times a day each. Amazingly enough, it seems to be running very smoothly lately, but they did have many rough spots in the last few months when the sites performance was really poor.

It seems that their issue is not the execution speed, but the Rails design itself. In a recent interview a Twitter developer Alex Payne said:

The common wisdom in the Rails community at this time is that scaling Rails is a matter of cost: just throw more CPUs at it. The problem is that more instances of Rails (running as part of a Mongrel cluster, in our case) means more requests to your database. At this point in time there’s no facility in Rails to talk to more than one database at a time. The solutions to this are caching the hell out of everything and setting up multiple read-only slave databases, neither of which are quick fixes to implement. So it’s not just cost, it’s time, and time is that much more precious when people can[’t]reach your site.

Emphasis was mine. The lack of support for multiple databases seems a huge bottleneck issue for high traffic sites. Most of us don’t even think about stuff like that when considering using a platform to build our applications with.

I still think RoR is a good platform. It just might not be ready for the enterprise scale apps like Twitter. Most of us however will never experience this issue - unless of course we get slashdotted or something. I’m confident that the Rails team will use the Twitter problems to improve scalability features in future releases.