Archive for the ‘How-to’ Category

Utilizing Caches.rb with Ferret

We needed to cache a Ruby class method calling the Ferret indexing engine.
Yurii Rashkovskii developed a great library called Caches.rb.

When I googled it out, it seemed very simple to use and promised to do EXACTLY what I need (even the default timeout was JUST IT). I especially liked the very Rails-like tutorial Don’t tell, show me!. However, it required quite some effort to make it work, mainly because of the rather sparse documentation. Still, in the end the usage is very elegant, the solution is simple and it does what it promises. Thank you, Yurii!

To help our esteemed readers get faster over that less agreeable middle phase, here are a few tips:

  • Downloading it: I tried gems but the gem list server seemed to be overloaded, and when it worked at last, I just got an older version (0.2.0). When checking out (or exporting) version 0.4.0 from SVN trunk directly, the trick was in finding out the latest working SVN URL:
    ruby script/plugin install http://svn.verbdev.com/rb/caches.rb/trunk

  • With all the typical Rails mixin stuff petrified in my mind, it took me a while to notice that caching should be declared AFTER the definition of the method to be cached, and not at the beginning of the class definition.
  • The example in the documentation shows it, but it’s easily overseen.

  • We do use Rails, so I included class_cache_storage Caches::Storage::Global as suggested here
  • For some reason (I suspect my shallow knowledge of Ruby ;-), I did not manage to successfully require ‘caches.rb’ from the plugin installation dir _#{RAILS_ROOT}/vendor/plugins/caches.rb/lib_, so I copied it to _#{RAILS_ROOT}/lib_, which helped.
  • For similar reasons, I had to use a workaround to extend the class definition with caching, instead of the recommended way of extending conf/environment.rb by ActiveRecord::Base.extend Caches::ClassMethods

So our class looks as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
require 'ferret'
include Ferret
require 'caches.rb'
 
class FIndex
  extend Caches
  ...
  def self.search(user=nil, results_per_page=10)
    ...
  end
  class_cache_storage Caches::Storage::Global
  class_caches :search
end

N.B.: The class to be cached works with Ferret and not the DB, so it did not inherit from ActiveRecord.

  • For a pure RoR developer, the terminology may be a little confusing (which indicates that Yurii can deal with more programming languages than just Ruby):
    • class methods mentioned in the library description are obviously just a shorthand for “the methods of a class”
  • in Yurii’s documentation, Ruby class methods are called static methods (as known in C/C++ or Java), and their caching is supported by class_caches (feature not available in caches.rb 0.2.0 from gems or RubyForge, but included in the more recent versions from SVN, like 0.4.0 we are using)

Calling Oracle stored procedure from rails

Sometimes it is necessary to reuse existing logic from stored procedures. This line of code shows how to call a stored procedure in Oracle.

ActiveRecord::Base.connection.execute('BEGIN do_the_calculation; END;')

From pictures to picturables

This article tries to explain how to convert existing class in Ruby on Rails to a class that can be used in polymorphic association class. As the beginning, I do recommend to read article about polymorphic associations. It explains what they are and how they work.

The whole process will be described on classes Picture (represents picture) and Item (an item that needs a picture).

1. First of all, it is necessary to create columns for the pictures table. The best way is to use migrations. So, create file e.g. 013_convert_pictures_to_polymorph.rb in your db/migrate directory. It should contain something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class ConvertPicturesToPolymorph < ActiveRecord::Migration
 
  def self.up
    # Change old item_id identifier to new picturable_id
    rename_column :pictures, :item_id, :picturable_id
    # Add type of association
    add_column :pictures, :picturable_type, :string, :length => 50
    # Fill in the type of association
    execute "update pictures set picturable_type = \"Item\""
  end
 
 
  def self.down
    # Bring it back
    rename_column :pictures, :picturable_id, :item_id
    remove_column :pictures, :picturable_type
  end
end

now run:

1
rake migrate

to create the columns.

2. Once the appropriate columns were created, it is necessary to change the Item class. Change the

1
  has_many  :pictures

to

1
  has_many  :pictures, :as => :picturable

3. Now change the Picture class. Change

1
  belongs_to :item

to

1
  belongs_to :picturable, :polymorphic => true

Make sure, there is no “item” left in the Picture class. If so, change it to picturable and make sure all picturables have the method you are using.

4. Creating a new class enriched by pictures is simple. Just add

1
  has_many  :pictures, :as => :picturable

to your class.

5. Last but not least, change your fixtures. The easiest way is to export the current data from your database. For this purpose I do use manage_fixtures plugin.

Good luck!

RSpec for Ruby on Rails

Behaviour driven development is currently in. The best ay how to get in touch with it is to setup your own environment and make few examples.Nevertheless, if you prefer to start with a bit of theory, go to http://behaviour-driven.org/.This article describes simple procedure to setup Rspec to work together with ruby on rails.

Installation of RSpec

The installation procedure described in documentation needed small improvement:

First of all, install the rspec gem

gem install -r rspec #mac users must sudo

Then install following gems:

  • rake # Runs the build script
  • rcov # Verifies that the code is 100% covered by specs
  • webgen # Generates the static HTML website
  • RedCloth # Required by webgen
  • syntax # Required by our own custom webgen extension to highlight ruby code
  • diff-lcs # Required if you use the -diff switch
  • win32console # Required by the -colour switch if you‘re on Windows
  • meta_project # Required in order to make releases at RubyForge
  • heckle # Required if you use the -heckle switch
  • hpricot # Used for parsing HTML from the HTML output formatter in RSpec’s own specs

Then continue with these steps:

svn co svn://rubyforge.org/var/svn/rspec/trunk rspec
cd rspec
rake install_dependencies
cd example_rails_app
export RSPEC_RAILS_VERSION=1.2.3
rake rspec:generate_mysql_config
mysql -u root -p &lt; db/mysql_setup.sql
cd ..change example_rails_app/config/database.yml to correspond to your configurationrake pre_commit

and…Make the first test.

Create new folder in your project called spec. Create a file named e.g. basic_test.rb and fill it with

describe "Sum computation" do  
  it "should return 2" do    
    (1+1).should == 2  
  end
end

run it with

spec spec/basic_test.rb

Your test should finish sucessfuly:

.Finished in 0.006001 seconds1 example, 0 failures

Working with rails

That’s great! Now, let’s make it running with your rails objects. Go to the root of your application and install rspec plugins:

ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec
ruby script/plugin install svn://rubyforge.org/var/svn/rspec/tags/CURRENT/rspec_on_rails

bootstrap your application with

ruby script/generate rspec

and start testing with the rails objects. Use rspec generator to create the first test:

ruby script/generate rspec_model user

It generates file spec/models/user_spec.rb file

require File.dirname(__FILE__) + '/../spec_helper'
describe User do  
  before(:each) do    
    @user = User.new  
  end  
 
  it "should be valid" do    
    @user.should be_valid  
  end
end

And now you can just extend the pre-generated file and enjoy it.

Ruby on Rails with Oracle

I am working on a prototype in an big company and they do store data in Oracle. It took me some time to set up RoR working with Oracle. So, here are the things you need to do.

First of all, there is a great tutorial on Oracle site: http://www.oracle.com/technology/pub/articles/haefel-oracle-ruby.html.
In fact, you need to:

Download Ruby OCI library from http://rubyforge.org/projects/ruby-oci8

Configure access to Oracle in database.yml


Create a sequencer for each table (rails uses it to generate id). The sequencer must follow naming convention (see script below). You can create one using:

Since I am using one of the non-english character sets and the Oracle instance uses ISO 8859-2 and it is not compatible with Windows code page, I had problems with encoding. To avoid it, it is necessary to set up variable NLS_LANG. I did it in environment.rb.

Now you should be able to access the data source, perform basic operations with data, and see the data correctly.