Archive for the ‘Ruby on Rails’ Category

Rails application not working, no error displayed, just error code 500

I was facing a strange problem. My application was working fine, but after some time it stopped to respond. It just returned error code 500. No error message on the screen, no error message in the error log, everything seemed to be fine.


I found few hints on the internet – reboot, delete all sessions… One of them recommended to run script/console. It worked fine, until I tried to get any data. Finally I got the error message:

And the problem was almost solved – problem with log rotation.


So, if you face the same problem, try to perform few operations in your rails console… and if you are lucky, you will find the bug.

Syntax error without obvious reason

I just made a bad experience with ruby I would like to share.

I wanted to upgrade my SuSE Linux 9.1 to version 10. Failed… during the upgrade process my machine ended up in a strange state. I was not able to boot neither from hard drive nor from Windows XP installation disk. I had to use my old Win 2000 installation CD to make it running.

As a consequence, I had to recreate the whole development environment. After few hours of work I started my application…

Before the installation it was running without any problem. After the environment was recreated, I was not able to render some views. It showed me strange syntax errors:

ActionView::TemplateError (compile error
./script/../config/../app/views/story/_showing_tags.rhtml:4: syntax error
_erbout.concat "	"
                	  ^) on line #4 of app/views/story/_showing_tags.rhtml:
…
…
…
_erbout.concat "                        ";  end ; _erbout.concat "\n"
_erbout.concat "</div>\n"
_erbout
end
Backtrace: ./script/../config/../app/views/story/_showing_tags.rhtml:4:in `compile_template'
c:/win32app/ruby/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_view/base.rb:307:in `compile_and_render_template'
c:/win32app/ruby/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_view/base.rb:292:in `render_template'
c:/win32app/ruby/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_view/base.rb:251:in `render_file'
c:/win32app/ruby/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_view/base.rb:266:in `render'
c:/win32app/ruby/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_view/partials.rb:59:in `render_partial'
c:/win32app/ruby/lib/ruby/gems/1.8/gems/actionpack-1.12.5/lib/action_controller/benchmarking.rb:29:in `benchmark'
c:/win32app/ruby/lib/ruby/1.8/benchmark.rb:293:in `measure'
…
…
...

In fact, the rails were complaining about the tabs before the embedded ruby commands

After changing the tabs to 2 spaces the application started… complaining about another characters.

I did some research and I was pointed to a ruby version. Before the reinstallation I was running 1.8.2. After the installation I took the latest one. Bad decision. It was caused by the ruby interpreter version.

So, if you face weird syntax errors with ruby 1.8.4 and you are sure about the syntax, try to change the version. I downgraded to 1.8.2 and it started to work again.

Visualize your Rails schema

While doing some Ruby on Rails code refactoring, I realized I’d like to visualize the database schema of the application.

An easy possibility is to print out db/schema.rb. This seems a bit too linear and little visual to me. OK, I’d better keep thinking.

An enterprise approach would be to take a CASE machinery and feed it with the create DB scripts. That is solid and reliable, but a kind of overkill. What’s more, a Rails app with convention over configuration can do well without foreign keys and so it usually does. This means that relations between tables are mostly implied by column names rather than explicitly declared as DB constraints. Thus, hardly any CASE tool can derive such relations from a DB schema.

OK, let’s try to go the Rails way and put together existing ingredients, add a little cream and see what we can get:

  • there are many UML modeling tools out there, although few of the free ones can reverse-engineer a DB schema
  • there’s the SchemaDumper in ActiveRecord, which generates the schema.rb based on DB reflection
  • there’s this standard XMI format for data interchange between modeling tools

OK, so let’s try and tweak the SchemaDumper to generate XMI, then import it into a UML modeling tool and get the schema diagram from there.

So, I morphed SchemaDumper into UmlDumper, which generates XMI in the widely adopted Rose flavor. E.g. a Typo blog database will result in schema.xml like this:

xmi.gif

Then I import this XMI into a UML tool – StarUML in my case – to get the basic picture. Yellow boxes are DB tables, grey boxes are presumed “virtual” tables referenced by columns in other tables.

raw.gif

I play a little with the layout and incorporate the “virtual” tables into the hierarchy. For completeness, I also add a few model classes, which show up only in Rails code, not in the database (manual entries in blue color):

main.gif

I export the diagram from the tool to print it, share it and enjoy.

Now, that’s it! The approach is quite universal (not yet true for UmlDumper), I can quickly reuse it in my further Rails projects, and so can you.

Note: for one-time use I created a rake task.

namespace :uml do
  desc "Generate an XMI db/schema.xml file describing the current DB as seen by AR. Produces XMI 1.1 for UML 1.3 Rose Extended, viewable e.g. by StarUML"
  task :schema =&gt; :environment do
    require 'lib/uml_dumper.rb'
    File.open("db/schema.xml", "w") do |file|
      ActiveRecord::UmlDumper.dump(ActiveRecord::Base.connection, file)
    end 
    puts "Done. Schema XMI created as db/schema.xml."
  end
end

For frequent use (fine-tuning the export), it is better to start the Rails console and call UmlDumper from there to avoid re-loading the whole Rails stack all over again.

tamtami.com story

My uncle started to work as a truck driver. I must say, it is a tough job. You are driving from Barcelona to Warsaw, then to Zagreb and …

He enjoys it. He travels a lot and see the whole Europe.

He has got one major problem. The problem is navigation. Since the truck drivers are payed for fast delivery, he desperately needs a navigation system. He came to me for help, since I “understand computers” – which in my family means I’m asked for advice on anything that uses electric power to operate.

He asked me to find a good GPS system for truck drivers. I thought it is an easy job, but actually it is not. I found several sites with special software for truck drivers (for a laptop+GPS device), a lot of sites with GPS devices, but I was not able to find any site where there woud be a review of GPS systems for truck drivers.

Since I “understand computers”, I took an open source system GrabTheMic and created site www.tamtami.com. It is a bookmarking site specialised on product and services reviews. Now while I’ve been digging through the world wild web, I’ve collected there bookmarks of the good GPS reviews I’ve seen. They’ve helped me to get started in the GPS stuff and now they can help someone else. So, that’s it! You can check out the bookmarks there, vote on the best ones, throw in your two pence worth, or use them to advise your friends and family.

Full text search in Ruby on Rails 3 - ferret

There are several possibilities how to use ferret in RoR. This post will show the easy way – using the acts_as_ferret plugin.

To show the syntax and code, I will use the same data objects as in the Full text search in ruby on rails 2 – MySQL

Installation

Ferret installation is easy

gem install ferret

will do the job.

In addition, it is necessary to install the acts_as_ferret plugin.

script/plugin install svn://projects.jkraemer.net/acts_as_ferret/tags/stable/acts_as_ferret

Setup

The most simple setup is

class Article > ActiveRecord::Base
  acts_as_ferret	
end

This is enough to make the full text engine working. Now you can test it in the Rails console

Article.find_by_contents("sybase")

If you have a lot of data to be indexed, be patient with the first run. It is slow, because the index needs to be built.

The acts_as_ferret with no argument indexes automatically all fields of the Article, including arrays of child objects. This behaviour could be overwritten. You can narrow the field set

# Index only id and body, not title
acts_as_ferret :fields => [ 'id', 'body' ]

Or you can widen the field set.

acts_as_ferret :fields => [ 'id', 'body', 'title', 'long_article' ]
 
# Compute the article length
def long_article
  self.body.length > 40
end

Note 1: see usage of long_article in Query syntax below

Note 2: once you change the structure of the index, you need to rebuild it. The easiest way is to stop your application and delete the index/~environment~/~Indexed object~ folder. It will be created automatically with the next search request.

Query syntax

Since ferret is a port of the lucene engine, it uses the same query syntax. I will show only a few queries that you can use.

For details see Lucene documentation

  # Search for pages with "sybase" keyword
  Article.find_by_contents("sybase")
 
  # "sybase" and "replication" keywords
  Article.find_by_contents("sybase replication")
 
  # "sybase" or "replication"
  Article.find_by_contents("sybase OR replication")
 
  # short articles about sybase
  Article.find_by_contents("long_article:(false) *:sybase")
 
  # articles containing similar words like "increase"
  # will return e.g. increasing
  Article.find_by_contents("increase~")

Pagination

Ferret is fast, ferret is flexible, but… it is not an active record object, so you cannot use the pre-defined pagination. You have to implement it on your own. Here is how we did it in our project www.tamtami.com.

1. Create full text search function in the model

  def self.full_text_search(q, options = {})
    return nil if q.nil? or q==""
    default_options = {:limit => 10, :page => 1}
    options = default_options.merge options
    options[:offset] = options[:limit] * (options[:page].to_i-1)
    results_ids = []
 
    num = self.ferret_index.search_each("*:(#{q})", {:num_docs => options[:limit], :first_doc => options[:offset]}) { |doc, score|
      results_ids << self.ferret_index[doc]["id"]
    }
    results = Article.find(results_ids)
    return [num, results]
  end

or more elegant, as proposed by Jens Kraemer

  def self.full_text_search(q, options = {})
    return nil if q.nil? or q==""
    default_options = {:limit => 10, :page => 1}
    options = default_options.merge options
    options[:offset] = options[:limit] * (options.delete(:page).to_i-1)  
    results = Article.find_by_contents(q, options)
    return [results.total_hits, results]
  end

2. Create method that creates paginator in application.rb

  def pages_for(size, options = {})
    default_options = {:per_page => 10}
    options = default_options.merge options
    pages = Paginator.new self, size, options[:per_page], (params[:page]||1)
    pages
  end

3. Perform the search in the controller

  def search
    @query=params[:query]
    @total, @articles = Article.full_text_search(@query, :page => (params[:page]||1))	  
    @pages = pages_for(@total)
  end

4. Use it in the article view

...
   <%= pagination_links(@pages, :params => {:query=>@query}) %>
...

Final word

The ferret fulltext engine is fast, flexible, but needs more programming than MySQL full text index.