Ruby on Rails Errors and Solutions
Contents
When you develop something in Ruby on Rails, you will most likely encounter strange errors here and there. These errors may look like language or framework bugs, but they are not. Most likely, they are programming bugs you were not aware of before you encountered them.
The reasons for that are twofold. First, Ruby is a dynamically-typed language, and this alone introduces subtleties you should know about. Second, the web framework values convention over documentation. It means that methods and functions should just work as expected, without making the user read the whole documentation page.
And when something just doesn't work, you'll have troubles finding the cause in the API docs. You'll have to google the exception message, and hope to find the cause.
This post is another contribution to this Exception-Driven Development, and lists some errors a Ruby/Rails programmer may make. Some of the errors were found via web search (I tried to provide a proper attribution where possible), and some of them were solved by my own. I'll try to keep this list up-to-date, and add more errors here as I write more Rails programs.
Generic Ruby Issues
Calling setter methods
You are setting a value of an ActiveRecord field from inside a method of your model, but it does nothing? You are doing it wrong. Perhaps, you write something like this:
But the value is reset after this method. What's happening? The field = ... line actually creates a new local variable, rather than calling the object's field=(value) method ActiveRecord has created for you. Just use self to distinguish:
Note that you don't have to do the same when you read from the field—unless you have created a local variable with the same name! This is why the second line of the method doesn't have to contain self in this case.
Sometimes this strikes you from a different angle. For instance, if you have a quality attribute in your model, and you want to set conversion quality with RMagick, you have to write:
because you can't easily access the outside's variable quality from inside the block, as it's routed to the RMagick object instead.
Other gotchas
You might have specified :false instead of false when you pass a hash attributes to Ruby. I devoted a separate post to this.
Surprising Bugs
Error to clean your cookies
If you have this error:
ActionController::InvalidAuthenticityToken in SessionsController#create ActionController::InvalidAuthenticityToken RAILS_ROOT: /home/rails/app/ Application Trace | Framework Trace | Full Trace /home/rails/app/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb:79:in `verify_authenticity_token' /home/rails/app/vendor/rails/activesupport/lib/active_support/callbacks.rb:178:in `send'
you should clear your cookies. Perhaps, you have deployed a different site under the same hostname. If this alone does not help, check if you have set up constant DOMAIN or SESSION_DOMAIN in your config (I had them in config/environments/production.rb), adjust them, and restart your server.
Strange remote_ip error
This error:
undefined method `remote_ip' for nil:NilClass
means that you accidentally named one of your actions "request". And you can't name your actions "request", as there's some clash when the engine wants to get a current request, but calls your controller method instead. Rename your action.
Spawn plugin and Rails 3
Your spawn plugin is throwing this kind of error:
spawn> Exception in child[26055] - NameError: uninitialized class variable @@connection_handler in ActiveRecord::Base
That means that it's too old for your current version of Rails. Upgrade it—to the latest commit it has (this is not on the master, but on its edge branch), or use it as a gem. If you use Rails3, here's the line for your Gemfile:
gem 'spawn', :git => 'git://github.com/tra/spawn', :branch => 'edge'
Commit 0e1ab99b worked for me, the corresponding gem version is 1.1). Source.
Unicode problems
UTF-8 regular expressions do not work by default? Add #coding: utf-8 as the first line of your ruby file. If it's an ERB or HAML template, add this at the beginning anyway.
If you want to make your application completely Unicode, from the database to the tips of your views, you should do all of the following.
- Make sure that all of your source code files are in UTF-8;
- Make sure you added # coding: utf-8 at the beginning of any source .rb file (views, initializers, library files) that actually contains non-ASCII characters;
- Make you database Unicode:
- make sure you set utf-8 character set for the database as a whole;
- set utf-8 character set for each table;
- set utf-8 character set for each text or string column in the table;
- the "default" rails gem doesn't support Unicode. Use mysql2 gem instead as your MySQL driver.
If you miss one of the steps, you may encounter problems. For instance, if you do everything except for the mysql2 gem, you may see these errors for your views:
Showing app/views/layouts/application.html.erb where line #48 raised: incompatible character encodings: ASCII-8BIT and UTF-8
If you do not set up the character set for the database, migrations may create new tables with latin1 encoding, and this may result in ?????????? instead of non-ascii lines in the data user enters to your DB.
Models, Databases, and Validations
Ever-failing presence validation
Do NOT add empty? method to your objects unless you really mean it! This can strike you from you back when you don't expect.
Assume you want to validate that a "belongs_to" association presents at save. You might use validates_presence_of for this. However, as specified in the documentation, it calls Rails' Object.blank? to check presence. It, in turn, calls empty? method (documentation) if it exists.
In my forum engine, I used empty? method to convey if the post's body is empty. Therefore, you couldn't answer to posts with empty bodies, because validation thought that such posts are nonexistent.
Instead of using a complex validation, I suggest renaming the empty? method. When the author of the next model forgets—or won't even happen to know—about this bug, he/she will still try to use validates_presence_of. It's better to make it work, following the principle of least surprise.
Model name clashes
You can't name your models like Ruby classes, i.e. Thread (conflicts with internal class for threading) or Post (conflicts with HTTP library).
It's interesting, that the default scaffolding automatically names your model "Threads" when you instruct it to create a "Thread" model to avoid conflict. However, you still need to specify the proper class name in associations:
Check the scaffolded controller for other declarative methods that may also need adjustment.
Using several databases in the application
If you want to specify several databases for your app (on a per-model basis), you can use a built-in ActiveRecord capabilities. Just add a section in your config/database.yml with a distinguished name (i.e. second_db instead of production), and add this to your model:
Troubles with making a form with validation but without database
Rails3 has a built-in solution for creating a form that use ActiveRecord-style validations, but are not backed up by a DB table. Indeed, not reusing this functionality would be a waste. But just including ActiveModel::Validations makes your form yeild errors like this:
undefined method `to_key' for #<Loginpost:0x000000038de700>.
Listen to a short RailsCast on ActiveModel, and learn how to add some magic to your model. Here's how it should look like:
Validation of non-database attributes
Want to validate the range of numbers in your temporary attributes? You write
but get a kind of "undefined method something_before_type_cast" error:
undefined method `quality_before_type_cast' for #<Image:0x7f579f5fe940> /usr/lib64/ruby/gems/1.8/gems/activerecord-2.3.14/lib/active_record/attribute_methods.rb:255:in `method_missing' /usr/lib64/ruby/gems/1.8/gems/activerecord-2.3.14/lib/active_record/validations.rb:1030:in `send' /usr/lib64/ruby/gems/1.8/gems/activerecord-2.3.14/lib/active_record/validations.rb:1030:in `validates_numericality_of' /usr/lib64/ruby/gems/1.8/gems/activerecord-2.3.14/lib/active_record/validations.rb:479:in `validates_each' /usr/lib64/ruby/gems/1.8/gems/activerecord-2.3.14/lib/active_record/validations.rb:476:in `each'
The error trace makes a hint about the solution:
For ActiveRecord attributes, these methods are automatically generated. However, for our attributes that are not backed by DB columns, we should create on our own.
Uniqueness validation column name error
I created a model, added an `validates_uniqueness_on`—uniqueness validation—and tried to create a valid record. However, I was getting the NoMethodError: undefined method `text?' for nil:NilClass error no matter how hard I tried:
NoMethodError: undefined method `text?' for nil:NilClass from /activerecord-3.2.2/lib/active_record/validations/uniqueness.rb:57:in `build_relation' from /activerecord-3.2.2/lib/active_record/validations/uniqueness.rb:25:in `validate_each' from /activemodel-3.2.2/lib/active_model/validator.rb:153:in `block in validate' from /activemodel-3.2.2/lib/active_model/validator.rb:150:in `each' ...
I checked the code, and realized that my uniqueness validation referred to an association name, instead of the database column name:
It seems that you must specify the exact database column name in the uniqueness validations since they are closely integrated with the database.
Connecting to a local database via TCP sockets
If you want to avoid using file sockets for connection to a local database, it's not enough to just remove the socket line. Rails will replace it with the default socket configuration if you use localhost as your host. To connect via a network socket, you have to change "localhost" to something else by adding an entry to /etc/hosts, for instance.
Housekeeping
Accessing methods from console
Contrary to the popular belief, there is a way to easily access helpers and other useful application methods from console. Here is a couple of examples:
>> app.project_path(Project.first) => "/projects/130349783-with-attachments" >> helper.link_to "Home", app.root_path => "Home"
You may read the complete guide here.
Get list of Rake/Capistrano tasks
When you use rake tasks, or a similar program (such as Capistrano), it's easy to forget what actions it provides. Googling for the list doesn't help either. Where can you find them?
They're right there:
These commands print the list of all tasks. With cap -e task:name, you can get a more extended help.
Redo specific migration
$ rake db:migrate:redo VERSION=20111122143422
Rake can also go several steps back/forward in migration application; you now know how to see the docs (rake -T).
Using Ruby 1.9 on Ubuntu
Ruby 1.9's default virtual machine is superior to that of 1.8. Besides, version 1.9 has
If you are using Ubuntu, you have "alternatives" mechanism for setting ruby version. But. please, do not forget to update alternatives both for ruby, and for gem command to 1.9! Otherwise your gems (such as passenger) may end up in an improper place, and won't run successfully.
MySQL gem and Mac
If you install mysql onto a MacOS with MySQL 5.5, you may encounter problems that show up as a strange exception:
rake aborted! Constant MysqlCompat::MysqlRes from mysql_compat/mysql_res.rb not found Constant MysqlRes from mysql_res.rb not found Tasks: TOP => db:migrate (See full trace by running task with --trace)
It turns out that the problem here is a wrong mysql gem version. Uninstall the existing gem, and install 2.7 version, fixing some errors afterwards with a symlink:
$ gem uninstall mysql $ gem install mysql -v 2.7 -- --with-mysql-config=/usr/local/mysql/bin/mysql_config $ sudo ln -s /usr/local/mysql/lib/libmysqlclient.18.dylib /usr/lib/libmysqlclient.18.dylib
Source: Sergey Ler told me about it.
Using Ruby 1.9 on Ubuntu
Ruby 1.9's default virtual machine is superior to that of 1.8. Besides, version 1.9 supports OS-level threading, and some multithreading bugs fixed.
If you are using Ubuntu, you have "alternatives" mechanism for setting ruby version. But. please, do not forget to update alternatives both for ruby, and for gem command to 1.9! Otherwise your gems (such as passenger) may end up in an improper place, and won't run successfully.
JavaScript in Rails
jQuery ajax events do not work
I used Unobtrusive jQuery JavaScript gem for Rails. I read in its Installaion instructions that jQuery is among its "requirements". I downloaded jQuery, and put it into my assets folder, and then included the //= lines into the application.js.
As a result, my jQuery didn't work. It sometimes worked, but its AJAX events did not fire although the server reported that queries had been made. The mistake was that I should had not downloaded and placed the jQuery js file into the assets folder. I should only had added the "require" lines into the application.js.
Thanks to StackOverflow... as usual.
Talking to Web APIs
Specifying POST and GET PARAMS at the same time
If you are to POST some HTTP data to a URL that has GET parameters, documentation used to elide this case. The correct way to do this is to create URI object, and supply it as a whole, not just uri.path.
res = Net::HTTP.post_form(URI('http://example.com/webservice.php?token=' + TOKEN + '&function=api&id=50'), {:post_param => post_value})
Alternatively, you may supply a URL instead of URI, but I recall we had issues with this, though the exact reasons are now forgotten.
Converting data structures to POST form data
It's strange that Rails doesn't have such a method (I couldn't find it in version 2.13). When you invoke API of a web service, you sometimes need to convert arrays, hashes and other structures to a result that looks like a HTML form that Rails itself uses. For instance, this structure:
should be "flattened" to a "form field name"-"form value" set like this:
The "solutions" found in the internet seem to have been written by programmers who are not aware of recursion. Here's the correct one I wrote:
Russian Support
Here's a gem that adds Russian support to your Rails messages in default form validation and helpers. Russian morphology differs from that of English. In this plugin, the issues with date and proper clause of plural nouns are solved, though the difference in nouns on form create/update nouns is not.