Wednesday, November 24, 2010

Rails TypeError (can't convert String into Integer) on save


RoR is fun !

Unless... you encounter some problem that google cannot explain ;)

So recently I've got some strange TypeError (can't convert String into Integer) in .rvm/gems/ruby-1.9.2-p0/gems/activerecord-3.0.3/lib/active_record/connection_adapters/abstract/database_statements.rb:319 when doing .save on my object.

Records were successfully saved into database but this error stopped app from execution.
I've investigated this a little, trying to find this mysterious String which ruby wants to convert to Integer.
Let me tell you a little about my object I want to save.
    class CreateSites < ActiveRecord::Migration
      def self.up
        create_table :sites do |t|
          t.integer :id, :null => false
          t.text :title, :null => false
          t.column :hash, :'varchar(32)', :null => false
          t.text :description, :null => false
          t.column :user_id, 'integer references users(id)', :null => false
          t.timestamps
        end
      end

      def self.down
        drop_table :sites
      end
    end

This is my migration file, clean and simple. Nothing can be wrong here, well that's a lie ;)

Ruby was complaining about my hash field, why ? Because every object in ruby has a hash method, which is used for eg. in comparison when doing Array.uniq (which is done in rails). Then when I created this migration, rails created a Class which was overwriting hash method (which returns int) to return the db value (which is string).
Sooooooo not cool ! Why this isn't documented anywhere ? Shame on you rails developers ! It should be red in migration guide - DO NOT USE "HASH" AS A FIELD NAME, IT WILL BREAK YOUR APP

11 comments:

Unknown said...

Man,

Thank you, very much
You really save my day

Incredible, how you discover it.

DO NOT USE HASH AS FIELD NAME IN YOUR APP, IF YOU'RE USING MYSQL

Regards

ola said...

I have exactly the same problem, but no 'hash' field in my db. How did you find out what field caused the error? I'd like to do the same to identify which field causes it in my case.

Oskar Wycislak said...

Hi Ola.

Well I did some debugging ;) Does your app crashing @ activerecord-3.0.3/lib/active_record/connection_adapters/abstract/database_statements.rb:319 ?
Mine did ;] You need to follow the white rabbit function by function to find a real cause of your crash. I dunno about other fields but you can check ruby object reference http://ruby-doc.org/core/classes/Object.html (checking array would be probably good idea too) versus your db fields, otherwise just follow the white rabbit ;)

ola said...

Yes, it breaks in exact the same place. In addition it works fine in rails 3.0.0.beta3 but fails in rails 3.0.0 and above.
I'm following the rabbit for hours now with no luck...
I've checked my db fields and none seems suspicious, but thanks for the clue - I'll look deeper into this.

Oskar Wycislak said...

Hi again.

You could try to break the code on line 318 after:
unless records.blank?
#break here
debugger

and here in irb do
records
and see how it looks like then do
records.uniq
and if it'll crash try to do
records.hash
and

records.each {|r| print r.hash, " "}

Those should return and integer, if they don't something is overwriting those methods and you should check this. If they do and app still crash with records.uniq I sugest you analyze further the Array.uniq method ans share with your findings ;)
Tip: 3990538779228481933 - seems to be a hash for nil ;)

ola said...

You were right! It was a problem with 'hash'. I was looking so much into db fields that I completly overlooked methods defined in the model...
There is a 'hash' method returning string and this is causing the problem.
Thank you very much for your help - you saved my day!

Robert said...

Thanks for sharing your solution. I ran into the same issue, but was approaching it from a totally different angle, you saved me hours of despair! I owe you a beer.

Eduardo said...

Man, I can't express how thankful I am right now.

Interestingly enough, all works really well, even with a hash field. The only thing that broke my app was when I tried to do a "destroy_all" (cascading).

Thanks, man!

ALL said...

I just can't believe... Still today they don't see this error.

Anders said...

Upvote. This was killing me. Thank you so much.

DaveL said...

Thanks for this, just spent a half hour fighting this issue!