venerdì 28 ottobre 2011

Using virtual attributes for multi-parameter form helpers in Rails

In a Rails application I am working on, I needed to setup a form with a field with a non-standard behaviour. The field represents a date object, so the FormHelper date_select helper looked great; however, the date to display was not the actual date to be set on the database, but the day before. Changing all the data on the DB was a bit risky, so I had to stick with this requirement.
I decided to use a virtual attribute to do this, as it seemed the most elegant solution, so I wrote this in my model:

def expire_date_minus_one_day
self.expire_date - 1.day
end
def expire_date_minus_one_day= date
self.expire_date = date + 1.day
end


And this in my controller:

<p>
<%= f.label :expire_date %>
<%= f.date_select :expire_date_minus_one_day %>
</p>


However, trying to send this data to the controller resulted in a "1 error(s) on assignment of multiparameter attributes" error.

The solution I found after some search was this one:

composed_of :expire_date_minus_one_day,
:class_name => 'Date',
:mapping => %w(Date to_s),
:constructor => Proc.new{ |item| item },
:converter => Proc.new{ |item| item }


Reference:
http://gabeodess.heroku.com/posts/14

mercoledì 20 luglio 2011

OSX Lion: "This disk cannot be used to start up your computer"

Today I downloaded the installer for OSX Lion from the App Store. I ran it, and when it came to choose the disk to install to, it told me that "this disk cannot be used to start up your computer". I had a setup with 4 partitions: the hidden EFI system partition, the Macintosh HD partition, and two linux partitions (an ext3 one + a swap one).

So, the solution was to resize the Macintosh HD partition. I booted my Mac from the Lion install DVD (you can burn it from the installer package, just search google to know how to do it), went into disk utility, checked all partitions for errors (this was necessary because I wasn't able to resize them otherwise) then I resized only the Macintosh HD partition shrinking it by some GBs.

After this, I ran the installer again and installation started smoothly.

HTH!

domenica 19 giugno 2011

Machinist vs Factory Girl: Machinist win!

Today I decided to verify if Machinist could be a good replacement for Factory Girl. In our project, we have a big problem with Factory Girl: even if you tell her not to hit the database, using the Factory.build method, if an object has associations, these are saved on the DB. And this causes a huge slowdown in specs using factories. We've been using Factory Girl for nearly two years, and if we could find a way to stop him hitting the DB, we could really have a huge improvent in our test suite running time.



To verify if Machinist could perform better, I set up a basic rails app. Look at this example:



# person.rb
validates_presence_of :address
# person_factory.rb
Factory.define :person do |p|
p.name 'John'
p.surname 'Doe'
p.association :address
end
# person_spec.rb
it "builds a valid person with factory girl" do
Factory.build(:person).should be_valid
end
view raw person_spec.rb hosted with ❤ by GitHub


If you do a tail -f log/test.log and you run this spec, you'll see something like this:



AREL (0.5ms) INSERT INTO "addresses" ("country", "planet", "created_at",
"updated_at") VALUES ('Italy', 'Earth', '2011-06-18 16:45:00.268423',
'2011-06-18 16:45:00.268423')
view raw gistfile1.sql hosted with ❤ by GitHub


The Factory.build method has to save dependencies on the DB to set the foreign keys on the objects and validate them.



Let's try with machinist:



# person.rb
validates_presence_of :address
# blueprints.rb
Person.blueprint do
name { "John" }
surname { "Doe" }
address { Address.make }
end
# person_spec.rb
it "builds a valid person with machinist" do
Person.make.should be_valid
end
view raw person_spec.rb hosted with ❤ by GitHub


This time, running tail on the test.log file and running the spec, doesn't shown any DB hit, and of yeah, we have a green test.



I verified this also by putting a debugger line after the validation and inspecting the DB from within the debugger after the validation has run - with FactoryGirl, it revealed an Address object saved on the DB, while with Mechanist it didn't.



I still haven't looked inside machinist to show how it handles this, but I'll do it soon, so keep in touch!

giovedì 10 marzo 2011

Howto: Run a rake task in sandbox mode

If you have a Rails rake task that somehow changes your DB data, but you want to be sure that the DB will be rolled back to its previous state after the rake task has completed, you can simply include this snippet right after your task definition:

ActiveRecord::Base.connection.increment_open_transactions
ActiveRecord::Base.connection.begin_db_transaction
at_exit do
ActiveRecord::Base.connection.rollback_db_transaction
ActiveRecord::Base.connection.decrement_open_transactions
end
view raw rollback.rb hosted with ❤ by GitHub


If you wonder where is this code coming from, it's directly from the rails console code.

venerdì 28 gennaio 2011

Rails 3 scopes with HABTM (has and belongs to many) relations

There are already many posts about this, but maybe this simple example will help you understand this subject even better.

# First model: tag.rb
# note that pomodori is a custom plural for pomodoro
class Tag < ActiveRecord::Base
has_and_belongs_to_many :pomodori
end
# Second model: pomodoro.rb
# here is how to define a Rails 3 scope through the join table:
class Pomodoro < ActiveRecord::Base
has_and_belongs_to_many :tags
scope :by_tag, lambda { |tag_text|
joins("join pomodori_tags, tags").
where('pomodori.id = pomodori_tags.pomodoro_id
AND pomodori_tags.tag_id = tags.id
AND tags.text = ?', tag_text)
}
end
view raw habtm_scope.rb hosted with ❤ by GitHub

martedì 18 gennaio 2011

invalid option: --with-pg-dir=/opt/PostgreSQL/9.0

I'd bet a lot of ruby devs actually found themselves stuck in this problem. You checkout a github repo, you run a bundle install and = duh = a gem cannot install because of a missing library.
You're sure you've already installed the library or dependency or whatever, but in a different path from the standard one (in this example I'm talking about PostgreSQL installed via the graphical installer instead of the ubuntu apt repo); so you issue the command

gem install pg -v0.9.0 --with-pg-dir=/opt/PostgreSQL/9.0

And you get this error message: invalid option: --with-pg-dir=/opt/PostgreSQL/9.0

What's the problem? You need to separate options with another pair of dashes:

gem install pg -v0.9.0 -- --with-pg-dir=/opt/PostgreSQL/9.0

And everything will work.