Ruby on Rails
Gotcha

Empty “def initialize”" causes illusive NoMethodError

Model:
###########


class Artist < ActiveRecord::Base
require ‘pp’
def initialize
end
def print
pp self.attributes { |col| col.value}
end
end

Test Case:
###########


require File.dirname(__FILE__) + ‘/../test_helper’

class ArtistTest < Test::Unit::TestCase
fixtures :artists
def test_create
new_artist = Artist.new
p “created artist”
new_artist.name = “name for artist”
p new_artist.print
end
end

Here’s the output:
###########


test_create(ArtistTest):
NoMethodError: You have a nil object when you didn’t expect it!
You might have expected an instance of Array.
The error occured while evaluating nil.include?
/usr/local/lib/ruby/gems/1.8/gems/activerecord-1.14.4/lib/active_record/base.rb:1772:in `method_missing’
./artist_test.rb:16:in `test_create’

Removing the:

def initialize
end

- Hank Beaver
h2. It just burns the edge

This is a page dedicated to all the small things that can go wrong and result in the massive uprooting of hair.

Mysterious message: “Rails Application Failed to Start Properly”, apparently caused by a simple “puts” command.

I spent a frustrating day finding out that while it’s ok echo variables to the stdout in IRB, the same puts statement will cause the ugliest un-traceable error ever if executed from the browser. I find no hint of error in the logger either. The solution? Never use “puts” anywhere.
- ?

Another solution is to put:

def print_debug(string)
echo string
end

in the application controller, and call
print_debug string
within your code elsewhere. Also allows you to have a consistent way to display your debugging strings with some editing to the parameters.

-KittyKate

App Silently Failing (HTTP 500 Errors)

If you are developing more than one app on the same box, and are switching back and forth, you may mysteriously get situations where nothing loads, but you don’t get errors. Clear the session cookie for the host (0.0.0.0 in most cases) and you will be fine.

If you’re using ActiveRecord for storing your sessions, make sure the sessions table exists, as it not being there can also cause silent failure. If not using AR for sessions, try removing the sess_ files from your temp directory.

has_and_belongs_to_many and Inheritance

I had a table called ‘users’ from which I inherited two types of users: Teachers and Students. (Model declaration looks like class Student < User) Obviously, a student has_and_belongs_to_many :teachers, and a teacher has_and_belongs_to_many :students. I had also created the students_teachers table, and could confirm that rows were being added properly. However, teacher.students was returning an empty array. The solution? Explicitly name the ‘users’ table by passing :table_name => 'users' in the has_and_belongs_to_many association.

—- What is gonna happen to the “teachers” table then? Is it gonna be used at all? (If you declare the table in the teachers model to be “users” that is.)

Given :table_name => 'users' Rails will not look for a table called ‘teachers’ at all. Any reference to objects of type ‘teacher’ are mapped to entries in the ‘user’ table with type = ‘Teacher’. [See SingleTableInheritance ]. If a table ‘teachers’ exists it will be ignored by this model. If it does not exist, no error will be raised. [jjw]

Hari Seldon?

Names You Can’t Use (aka reserved words, keywords)

Can’t make your \ActiveRecord class work? You may have named it something that’s already defined in Ruby or Rails. For a list of names you can’t use:

ruby r config/environments/production -e ‘print Object.constants.sort.join(", ")’

Special Note:
The above does not work for newer versions of Rails .13 +, you can run it this way…
ruby -r config/environment -e ‘print Object.constants.sort.join(", ")’

- Brett Stauner

Speical Special Notice
If you’re running rails > 1, the above will not work. use instead:

./script/runner ‘print Object.constants.sort.join(", ")’

—David Salamon

Apache/Lighty reserved words not the same as Webrick

Webrick has more reserved words than Apache or Lighty. For example, Log is not a reserved word in Lighty or Apache, but it is in Webrick. Be sure if you are running Webrick for development and Lighty or Apache for production you understand these differences to help prevent later frustration.
JeremyDurham

See the full list of ReservedWords which also includes reserved SQL words

—SamStephenson

There are currently two tickets open about this:

  1. ticket #751 Private Methods should be documented somewhere
  2. ticket #752 Override methods should fail fast

Also note that numerous field names have special properties. See the full list of MagicFieldNames.

The Nil Thing

In Ruby, nil.id is 4. This means that any time you try to take the id of something that’s nil, you get 4. In turn, this can lead to problems in Rails.

For example, let’s say you have a Teacher object, and you believe the Teacher has a Student. So at some point you do:

sid = teacher.student.id

to get the student’s id. But what you’ll get, if Teacher has a student method but this particular teacher doesn’t have a student, is 4 — because teacher.student will give you nil. Since the code won’t fail, you might not realize that somewhere else there’s a bug that is causing the Teacher not to have been assigned a Student.

So be alert for unexpected retrievals of things with id 4!

DavidBlack

Note that this will finally be changed in future Ruby versions. For now you can try helping yourself with something like this:

def nil.id() raise(ArgumentError, "You are calling nil.id!") end

(Just put the code into your ApplicationHelper file or somewhere similar.)

FlorianGross

Also beware that an empty string evaluates to true, so it will be displayed when you do

<pre> <% if work.name %> <h2><%= work.name %> <% end %>

To check if a string contains nothing, just use blank?. This is a convenience method made for you by Rails on all objects.

<pre> <% unless work.name.blank? %> <h2><%= work.name %>

<% end %>

—Julik

Beware of class-level attributes.

Some Rails environments (mod_ruby and FCGI) persist class configurations between requests, so you might shoot yourself in the foot when using class-level attributes when handling actions. It might seem convenient to store something there, but it might be that another user will be interacting with the same class (and his requests will use the same class attribute). Be also aware that class methods that change class state are not reverted between requests, so if you do

<pre> class MyController < ApplicationController def some_action #lets turn off the layout just for this action MyController.layout = false end end

it will actually disable layout for all subsequent requests to this controller on this application instance (Apache process or FCGI handler).
—Julik

20+ Rails gotchas by one user

Collection of my Rails gotchas here: http://www.ruby-forum.org/bb/viewtopic.php?t=14

To Hari Seldon?: I don’t know why you deleted this before – it looks like a relevant content
AlexeyVerkhovsky

Alexey, the phpBB install it’s on seems to be insecure.
MikeSugarbaker

Alexy, the site has been shut down due to security problems – can you paste the 20+ gotchas here?
—DennisSutch

has_and_belongs_to_many + validations

I was trying to associate a user with an issue (for a simple ticket tracker), but every time I did:

issue.users << user

Things would silently fail. The problem turned out to be that the validations were again being checked for the user object (specifically the password_confirmation, which I didn’t have because the record had already been saved) . Adding ‘:on => :create’ to that validation cleared up the problem.

BenBytheway

The symptoms of this problem can be seen in the log as:


SQL (0.000609) BEGIN
SQL (0.000540) COMMIT

and someobject.save silently failing. If you look at the error attribute of someobject:

logger.debug someobject.errors.to_yaml

you’ll see something like this:

users:
– &id002 !ruby/object:User
[…]
errors: !ruby/object:ActiveRecord::Errors
base: *id002
errors:
password_confirmation:
– “can’t be empty”

You are most likely to run into this problem when using LoginGenerator.
— Tomas Pospisek

Better yet, if you’re using LoginGenerator, you should set both the password and password_confirmation to ’’ before saving, and the before_update filter will take care of that validation for you. Setting it to only validate on creation is asking for trouble.
JoelYoung?

From the trivial-once-you-get-it box:

Q: The application works on several nearly-identical boxes, but on one instead of running the dispatcher it shows the dispatcher source. ExecCGI? is good, all the directory permissions are the same, and dawn is comming soon. rsync claims that all the files in the application directories (except the logs) are as identical as you can get. And the logs aren’t showing anything. What in the heck is the problem?

A: FastCGI? isn’t installed right on that box. Change it’s .htaccess to use .cgi and make sure to fix it after you get some sleep.

MarkusQ

RMagick results in your apps going mental, memory wise

RMagick uses stubs to access the lower level C objects, and doesn’t actually know about the memory used by them. Thus, the garbage collector doesn’t get kicked off when it should, and this results in massive memory usage.

The solution is to use RMagick, and when it’s done its thing, insert a call to GC.start to trigger the garbage collection.

There’s chapter and verse on this in the RMagick forums here : http://rubyforge.org/forum/forum.php?thread_id=1374&forum_id=1618, but it’s hidden away a bit. I happpened on it by accident when heading over there to raise a bug report :-)

Anyway, an example:


  def self.new()
    new_image = super
    new_image.created_at = Time.new
    new_image.updated_at = Time.new
    new_image.full_image_mimetype = 'image/jpeg'
    new_image.thumbnail_image_mimetype = 'image/jpeg'
    new_image.full_image = Binary.new
    new_image.thumbnail_image = Binary.new

    blank = Image.new(240,240) {
      self.background_color = 'white'
      self.format = 'jpeg'
    }
    new_image.full_image.binary_data = blank.to_blob
    blank = Image.new(75,75) {
      self.background_color = 'white'
      self.format = 'jpeg'
    }
    new_image.thumbnail_image.binary_data = blank.to_blob
    # Done with RMagick, so trigger GC to get rid of those pesky objects
    GC.start
    return new_image
  end

This simple fix, 2 lines to my model, took an app that was regularly gobbling up 250MB+ per instance and requiring hourly cronned restarts back down to the expected 20-30M or so, and stable in memory usage from day to day.

TufTy

Pathname Issue on Windows when trying to run AWS Scaffolding

Following the ActionWebService manual , you get to the point where you add the “web_service_scaffold :invoke”, and test in a browser. You are greeted with:

Errno::ENOENT in Backend#invoke


No such file or directory ...

The problem is that the Pathname class makes some assumptions about absolute paths that don’t play well with others, if they’re running on windows. (In my case, my rails root was on drive D:, while my ruby installation was on drive C:, haven’t determined if this matters or not) Here’s a (slightly tested) patch for ruby/lib/ruby/1.8/pathname.rb YMMV


--- ruby/lib/ruby/1.8/pathname.rb       2004-12-12 09:04:31.000000000 -0700
+++ ruby/lib/ruby/1.8/pathname-new.rb   2005-06-09 16:21:30.453125000 -0600
@@ -309,20 +309,29 @@
   # No arguments should be given; the old behaviour is *obsoleted*.
   #
   def realpath(*args)
+    require 'rbconfig'
+
     unless args.empty?
       warn "The argument for Pathname#realpath is obsoleted."
     end
     force_absolute = args.fetch(0, true)

-    if %r{\A/} =~ @path
-      top = '/'
+    is_absolute = %r{\A/}
+    top = '/'
+
+    # Win32 hacks
+    if Config::CONFIG["arch"] =~ %r{cygwin|mingw32|mswin32}i
+      is_absolute = %r{\A[A-Za-z]:/}
+      top = ''
+    end
+
+    if is_absolute =~ @path
       unresolved = @path.scan(%r{[^/]+})
     elsif force_absolute
       # Although POSIX getcwd returns a pathname which contains no symlink,
       # 4.4BSD-Lite2 derived getcwd may return the environment variable $PWD
       # which may contain a symlink.
       # So the return value of Dir.pwd should be examined.
-      top = '/'
       unresolved = Dir.pwd.scan(%r{[^/]+}) + @path.scan(%r{[^/]+})
     else
       top = ''

solo

You’ll also want to be changing around absolute
def absolute? is_absolute = %r{\A/} =~ @path ? true : false #added # Win32 hacks if Config::CONFIG["arch"] =~ %r{cygwin|mingw32|mswin32}i is_absolute = %r{\A[A-Za-z]:/} end #end added is_absolute end
h3. Incorrect id values being generated in :finder_sql

I discovered that any SQL where the value reference #{foo} is used will generate an incorrect value for foo when the SQL appears in double quotes ("). The solution is to use single quotes (’).

See also this message posting .

Apps break when moving from 0.12.1 to 0.13

I found all of my major apps broke when upgrading to Rails 0.13, but simple ones did not. It turned out to be a change in Routes. Routes will now not accept integers in route parameters. If you quote them, your app will work in 0.13.

Peter Cooper?

IE fails to render effects, with “Object does not support this method or property” error.

IE failed to render effects with the new prototype.js and effects.js on my pages. Safari and Firefox were fine. All attempts to run effects got a “Object does not support this method or property” error. After an hour of playing around, I found that having an element with an id of “options” on the page causes it. Change any elements with an id of “options” to any other name, and it works great.

Peter Cooper?

Method Filters and Controller Inheritance

I often create an administrative interface by extending a controller, overriding a few actions, and beefing up filtering. Beware that you may not get what you’d expect:

<pre> class PublicController < ApplicationController before_filter :filter_everyone, :except => 'index'

def index render :text => ‘Hi! This is the index.’ end def notindex render :text => ‘Hi! This is not the index.’ end private def filter_everyone false end

end

class ProtectedController < PublicController
before_filter :filter_everyone
end

I thought ProtectedController#index would yield a blank page because I intended the before_filter in that class to apply to every action. However, since no conditions were provided and it uses the same method as the before_filter in PublicController, it’s stuck with the old conditions. A quick fix is to explicitly provide the desired conditions, as in:

<pre> class ProtectedController < PublicController before_filter :filter_everyone, :except => '' end</pre>
Matt Walker

Select for single associations needs _id on the name

Given:
<pre>class User < ActiveRecord::Base belongs_to :frobble end</pre>

Find the bug that causes Rails to burp Frobble expected, got String:

<pre>collection_select(:user, :frobble, @users, :id, :name)</pre>

Hair loss ends when it becomes :frobble_<i>id</i>.

RyanPlatte

This is probably basic, but Ruby uses elsif, NOT elseif.

The LIMIT keyword used in id-query, a bug?

I notice the following SQL when pulling out a single record:

<pre> SELECT * FROM categories WHERE (categories.id = 2) LIMIT 1 </pre>

This is a bug in my eyes. If there were > 1 records with this id, the database column is faulty setup and I would want to know as soon as possible.

Association Collections Override Enumerable#find

As documented
collections returned from an association collection (added by has_many or has_and_belongs_to_many override Enumerable#find in a manner which is incompatible with the original. Consider using its alias Enumerable#detect if you need the original functionality.

John-Mason

You can’t simply assign to self in destructive methods

You can’t do e.g.

def oos_to_aas! self = self.gsub(“o”, "a") end

but rather

self[0..-1] = self.gsub(“o”, "a")

or

replace(gsub(“o”, "a"))

as “self” is an object, not a variable. Of course, in the example above, you could simply do

self.gsub!(“o”, "a")

Controllers do not stop executing code after a redirect_to or render

This code will cause an NilError:

unless @user redirect_to index_url end title = "Hello, {#user}!"

The reason is that the controller code does not stop executing at encountering a redirect_to or render. The redirect or render is simply queued until the controller is done. The solution is to either use an else like

unless @user redirect_to index_url else title = "Hello, {#user}!" end

which seems to be the idiomatic way, or (less elegant, perhaps?) to return from the controller to stop its further execution:

unless @user redirect_to index_url return end title = "Hello, {#user}!"

The alternative form

redirect_to index_url and return

looks a bit cooler.

if you’re doing a redirect_to from a before_filter, you can return false to end execution.

Stylesheets:

Its in the documentation, but if you are trying to print your web page, be sure to note that the default for stylesheet_link_tag is :media => “screen”. This snafued me. Didn’t notice it until 6 hours later. I was reformatting my screen in a thousand different ways to make everything really simple, only to have NO STYLESHEET for printing. I should have just set :media => “all” or created a separate stylesheet for printing.

SOAP API and mixed datatypes

If your application features a SOAP API, when running in production mode, your API might break if it recieves requests using the 1999 schema ie:

<?xml version"=>"\"1.0\" encoding=\"UTF-8\"?><SOAP-ENV:Envelope xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\" xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\" SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><SOAP-ENV:Body><namesp919:FooBar xmlns:namesp919=\"http://foo.bar.com/api/v2\"><token xsi:type=\"xsd:string\">x

1

2

The UR-Type datatype seems to be especially problematic.

Works fine when the requests all use the 2001 schema, and also seems to work fine in modes other than production…

Anyway, our kludge work-around is to inspect each request in a before_filter, and if it matches “www.w3.org/1999” or “ur-type” we do:

load 'xsd/datatypes1999.rb'

and then in an after_filter we do:

load 'xsd/datatypes.rb' unless XSD::Namespace == "http://www.w3.org/2001/XMLSchema"

(XSD::Namespace is changed by loading datatypes1999.rb).

Field observers

observe_field tags need to be declared AFTER the field that is being observed in the document. Otherwise you get javascript errors

Inflector doesn’t work as expected for generation scripts

When pluralization rules are added to the environments.rb inflector rules, they don’t hold true for the models within a module

Example:


Inflector.inflections do |inflect|
inflect.uncountable “media”
end

Generate an Admin scaffold for Media

C:\Projects\media_app>ruby script/generate scaffold Admin::Media
create  app/controllers/admin
create  app/helpers/admin
exists  app/views/admin/medias
create  test/functional/admin
dependency  model
create    app/models/
create    test/unit/
create    test/fixtures/
create    app/models/medias.rb
create    test/unit/medias_test.rb
create    test/fixtures/medias.yml
identical  app/views/admin/medias/_form.rhtml
create  app/views/admin/medias/list.rhtml
create  app/views/admin/medias/show.rhtml
create  app/views/admin/medias/new.rhtml
create  app/views/admin/medias/edit.rhtml
create  app/controllers/admin/medias_controller.rb
create  test/functional/admin/medias_controller_test.rb
create  app/helpers/admin/medias_helper.rb
create  app/views/layouts/medias.rhtml
create  public/stylesheets/scaffold.css
Loaded suite script/generate
Started

Finished in 0.0 seconds.

0 tests, 0 assertions, 0 failures, 0 errors

You will notice it does not use media; rather it uses medias

To work around this, add admin::media to the inflection settings:

Inflector.inflections do |inflect|
  inflect.uncountable "media", “admin::media”
end

More info on the issue on my blog

That’s all!

- Brad Gessler

Oracle oci does not like fields named ‘User’

If you try to add a record to a table with a field named ‘User’ you can expect an error like the following:

ActiveRecord::StatementInvalid in UseradminController#create

OCIError: ORA-00928: missing SELECT keyword: INSERT INTO gcousers (user, app, role, id) VALUES

RAILS_ROOT: c:/RailsApps/GCO/config/..

Renaming the field to something like ‘Userid’ gets rid of the problem.

Method called as “process” in controller

Status: 500 Internal Server Error Content-Type: text/html
Application error (Apache)

Change this error message for exceptions thrown outside of an action (like in Dispatcher setups or broken Ruby code) in public/500.html

It is a very bad idea to call a method named process in the controller.
def process end