Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ActiveRecord to_i method removed in Rails 3.2.9

Upgraded to Rails 3.2.9 today from 3.2.7 and it appears that the method "to_i" has been removed from ActiveRecord.

Is this by design? Or is it a bug? I cannot find any mention of it in the change notes. This is going to impact a lot of code.

thanks!

like image 993
vanboom Avatar asked Nov 12 '12 18:11

vanboom


3 Answers

The #to_i method never existed, however the way assigning objects to values has changed in Rails 3.2.8.

Given the following:

class Lecture < ActiveRecord::Base
  has_one :professor
end

Previously you could assign a professor to a lecture like this:

@lecture.professor = Professor.find_by_id(1)

Or like this:

@lecture.professor_id = Professor.find_by_id(1)

In the first case everything is simple as the professor association expects a professor object. In the second case though ActiveRecord performed some magic to coerce the id from the professor, as professor_id expects a integer instead.

In Rails 3.2.8 and above that magic no longer works. It is nice in a way as it is a hint you are probably doing something wrong. For example, if there isn't a professor_id column in the database, but just professor which expects an integer, assigning like this will no longer work.

It looks like this will be reverted to the previous behaviour in Rails 3.2.11.

like image 129
Luca Spiller Avatar answered Nov 08 '22 04:11

Luca Spiller


There has been one change with regards to "to_i" method in Rails 3.2.9, but that deals with the columns and not with the tables. See here.

So in your code, if you were passing entire object instead of column value, it was failing silently before. But now it will actually call the "to_i" method on the object and raise exception.

like image 37
websymphony Avatar answered Nov 08 '22 04:11

websymphony


I ran into the same error. It's not that ActiveRecord lacks #to_i but something else, which in my case involves the factory_girl gem.

factory_girl (4.1.0)
factory_girl_rails (4.1.0)

Here's an isolated case of the difference:

rails _3.1.0_ new rails31
cd rails31
bundle install
rails g scaffold note title:string contents:text
rails g scaffold user name:string
rails g migration add_user_id_to_notes user_id:integer
rake db:migrate

Then in the console:

require 'factory_girl'
FactoryGirl.define { factory :note }
Factory(:note, :user_id => User.first, :title => 'foo')
  User Load (0.1ms)  SELECT "users".* FROM "users" LIMIT 1
  SQL (0.5ms)  INSERT INTO "notes" ("contents", "created_at", "title", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?)  [["contents", nil], ["created_at", Sun, 13 Jan 2013 21:29:36 UTC +00:00], ["title", "foo"], ["updated_at", Sun, 13 Jan 2013 21:29:36 UTC +00:00], ["user_id", 1]]
 => #<Note id: 3, title: "foo", contents: nil, created_at: "2013-01-13 21:29:36", updated_at: "2013-01-13 21:29:36", user_id: 1> 

However, if I do the same sequence of steps with:

rails _3.2.11_ new rails3211

Then in the console I see:

1.9.2-p290 :001 > require 'factory_girl'
 => true 
1.9.2-p290 :002 > FactoryGirl.define { factory :note }
 => [] 
1.9.2-p290 :003 > Factory(:note, :user_id => User.first, :title => 'foo')
  User Load (0.1ms)  SELECT "users".* FROM "users" LIMIT 1
   (0.0ms)  begin transaction
  SQL (24.5ms)  INSERT INTO "notes" ("contents", "created_at", "title", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?)  [["contents", nil], ["created_at", Sun, 13 Jan 2013 21:33:03 UTC +00:00], ["title", "foo"], ["updated_at", Sun, 13 Jan 2013 21:33:03 UTC +00:00], ["user_id", nil]]
   (2.4ms)  commit transaction
 => #<Note id: 1, title: "foo", contents: nil, created_at: "2013-01-13 21:33:03", updated_at: "2013-01-13 21:33:03", user_id: nil> 

Note the nil user_id for Rails 3.2.11

like image 2
Ultrasaurus Avatar answered Nov 08 '22 03:11

Ultrasaurus