Ruby on Rails: pros and cons

Things I like about Ruby on Rails

Transparent mapping between database tables and models

In general, you don’t need to drop down from the level of Ruby code (to the level of SQL queries). You query your objects using directly using Ruby statements and Rails worries about managing all the database queries for you. The level of database abstraction is extreme.

Migrations

Migrations are database agnostic, allowing you to specify your database scheme in Ruby code rather than using database-specific SQL. This makes it very easy to, for example, develop locally using SQLite and deploy remotely using MySQL.

Incremental/iterative development model

Again thanks to migrations, you can make incremental changes to the database schema as you go without fear of breaking things. You don’t have to sit down and design your entire database schema from scratch before you start writing code, and you don’t have to worry about making painful changes to the schema down the road (because changes aren’t painful).

Testing toolchain

Every application comes with all the testing infrastructure built-in allowing you to do test-driven development/behaviour-driven development or at least test-enhanced development.

It uses Ruby

Rails is written in Ruby, which delivers:

Things I don’t like about Ruby on Rails

Inconsistent behaviour of generate controller and generate scaffold

script/generate scaffold User

Will produce a controller file named users_controller.rb but:

script/generate controller User

Will produce a controller file named user_controller.rb.

It’s still not clear to me how these things should be named. It seems that models should be singular, database tables plural, but controllers? Plural? If so, why does the scaffold command use the plural form and the controller command the singular?

Even in published books I note that many of the examples I have use singular controller names and others have plural, but given that the scaffold command creates views with plural names, there is a discrepancy between viewing stuff created with the scaffold command (nicely CSS formatted) and stuff done using a manually generated controller (singular) with a "scaffold :" declaration in the controller.

Answer

From IRC:

 <tpope> wincent: plural is conventional but not required like singular models are
<motion> wincent; name the controller BillyBob if you want
 <tpope> wincent: and yeah, it doesn't have to match up with a model
 <tpope> wincent: actually script/generate scaffold generates a singular model name. it then pluralizes 
         that model name if no controller name is specified

So the rules of thumb are:

  1. Call your controllers whatever you want
  2. When using generate scaffold, Rails will create a singular model (compulsory) and a plural controller
  3. When using generate controller, Rails will use whatever name you pass in
  4. Therefore for consistency it is a good idea to pass a plural controller name in to generate controller

Documentation shortcomings

In general I find the documentation (http://api.rubyonrails.org/) too hard to navigate, cluttered and overly concise. Some attempts at filling the gaps are available elsewhere:

How are booleans handled?

As an example, when you declare a table column as having type :boolean, how is that actually stored in the database? Is "true" the number 1? The letter "t"? (Or string?) Or is it "true"? Or "TRUE"? Is it database dependent?

All of these questions are left unanswered by the documentation. In my local SQLite-based setup it appears that true boolean values are stored as the letter "t" when I create a table column as follows:

t.column :is_superuser, :boolean, :default => false

The documentation for find has an example which looks a bit like a boolean:

:conditions => "administrator = 1"

That won’t work for me; I instead have to use:

:conditions => ["administrator = 't'"]

Is there any way of expressing this condition without using database-dependent code? The documentation for create_table says nothing; the documentation for column says only:

The type parameter must be one of the following values: :primary_key, :string, :text, :integer, :float, :datetime, :timestamp, :time, :date, :binary, :boolean.

It provides no further information about these types. If Rails allows me to create records with :boolean types in a database-indepedent way (eg. User.create :is_superuser => true) what then is the database-independent way of querying based on that boolean?

Update: More information on booleans

Partial answer: http://wiki.rubyonrails.com/rails/pages/HowtoUseBooleanColumns

Definitive answer: http://www.bigbold.com/snippets/posts/show/2086

:conditions => ['is_superuser = ?', true])

Alternative, prettier answer: "Dynamic attribute-based finders":

User.find_all_by_is_superuser(true)