Wednesday, February 18, 2009

RoR scaffolding breaks DRY principle

Nothing special, but I just realized that Ruby on Rails scaffolding breaks one of RoR's main principles - "Don't Repeat Yourself" (or DRY). When creating new and edit views for a new model, the exact same form is shown in both views:

>script/generate scaffold articles title:string body:text
...
create app/views/articles/index.html.erb
create app/views/articles/show.html.erb
create app/views/articles/new.html.erb
create app/views/articles/edit.html.erb
create app/views/layouts/articles.html.erb
...

If we look at new.html.erb we see

<% form_for(@articles) do |f| %>
<p>
<b>Title</b><br />
<%= f.text_field :title %>
</p>

<p>
<b>Body</b><br />
<%= f.text_area :body %>
</p>

<p>
<%= f.submit "Create" %>
</p>
<% end %>

And looking at edit.html.erb we see

<% form_for(@articles) do |f| %>
<p>
<b>Title</b><br />
<%= f.text_field :title %>
</p>

<p>
<b>Body</b><br />
<%= f.text_area :body %>
</p>

<p>
<%= f.submit "Update" %>
</p>
<% end %>

Looks like we are repeating ourselves here. If an object has many properties the amount of repeated code increases greatly.


The solution to this is using a partial for the fields and I think scaffold generator should be smart enough to do something like this:

>script/generate scaffold articles title:string body:text
...
create app/views/articles/_form_fields.html.erb
create app/views/articles/index.html.erb
create app/views/articles/show.html.erb
create app/views/articles/new.html.erb
create app/views/articles/edit.html.erb
create app/views/layouts/articles.html.erb
...

Making new.html.erb look like

<% form_for(@articles) do |f| %>
<% render :partial => 'form_fields', :locals => { :f => f } %>

<p>
<%= f.submit "Create" %>
</p>
<% end %>

Monday, February 9, 2009

Multi-column indexes in Ruby on Rails with MySQL

Nothing special, but I wanted to share two things that I learned yesterday while adding a multi-column index for one of my Ruby on Rails projects:

  1. The book I use didn't show an example of what the declaration of such index could be in a migrations file. So in case you were looking for such an example, here it is:

    add_index :table_name, [:column1, :column2, :column3], :unique => true, :name => 'some_name_here'

    So, just to clarify, add_index takes 3 parameters: name of the table you are adding index to, an array of column names to include in the index (could be just 1), and a hash of options that could specify whether the index is unique and assign a specific name to it (only these two options are supported by default).

  2. When creating an index using a number of columns with long names I ran across an issue with limits on index name in MySQL. Here is the error message:


    Mysql::Error: #33000Identifier name 'xxxx_xxx_xxx_xxx' is too long


    Where xxx were names of columns. When creating an index, MySQL joins together the names of the columns to create index name; however, there is a limit of 100 characters so if all names together in one string are longer you will get that error when trying to create an index.


    The solution is simple. Just use the name => 'some_custom_short_name' as an option to add_index function call and supply your own short name for the index.



Hope this helps someone.



Here is this info in the context of a migration:

class CreateTagLinks < ActiveRecord::Migration
def self.up
create_table :tag_links do |t|
t.integer :tag_id
t.integer :tagger_id
t.integer :url_id
t.boolean :is_accepted
t.timestamps
end

add_index :tag_links, [:tag_id, :tagger_id, :url_id], :unique => true
end

def self.down
drop_table :tag_links
end
end

Wednesday, February 4, 2009

Hello, World!

After all these years of reading blogs I finally decided to start my own. Nothing special here - I'll just share some thoughts and findings from the work side of life. I'm a geek at heart so I think a lot of content here will be fairly geeky; well, maybe someone will find it useful. Later...