Rails 3.1.1: STI type column reader is not defined on ruby 1.8.7-p352 until you access the column directly #3614

Closed
jrafanie opened this Issue Nov 11, 2011 · 4 comments

3 participants

@jrafanie

Using a vanilla app via rails new with a simple STI between User and SubUser with rails 3.1.1 with ruby 1.8.7-p352: SubUser#type raises a deprecation warning on ruby 1.8.7-p352 ((irb):1: warning: Object#type is deprecated; use Object#class) until I access the user's type column via user[:type], or read_attribute or manually create a new user.

This issue does not occur with ruby 1.9.2-p290.

It appears that since ruby 1.8.7 has a type method, the rails column reader type is not being defined early on and some other code path defines it later on although too late if I only ever go through the type reader.

Because 1.9.2 does not have this type column, my type reader method is defined in the earlier code path and everything works.

Any ideas where I should look in the code to propose a fix?

See this gist for a basic app and overview:
https://gist.github.com/1359653

@jrafanie

So, lib/active_record/attribute_methods.rb delay loads the attribute methods until the first request for anyo of them by going through method_missing. The problem is that in ruby 1.8.7, the method 'type' is defined and raises the deprecation warning when called instead of going through method_missing and defining the "real" attribute methods.

Once you call respond_to? or any other attribute methods, all attribute methods get defined including the type column. See below, demonstrating the delay loading of the of the attribute methods (name and type) and how the 'type' accessor does not define the attribute methods but 'name' does.

Note, I'm unable to recreate this in test since loading fixtures for a STI class will call end up defining the attribute methods via calls to any of the non-'type' accessors.

joerafaniello@:~/Code/playground/rails311_type_method$ rails c
Loading development environment (Rails 3.1.1)
ruby-1.8.7-p352 :016 >

ruby-1.8.7-p352 :017 > SubUser.first.methods.grep("type")
SubUser Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."type" IN ('SubUser') LIMIT 1
=> ["type"]
ruby-1.8.7-p352 :018 > SubUser.first.methods.grep("name")
SubUser Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."type" IN ('SubUser') LIMIT 1
=> []
ruby-1.8.7-p352 :019 > SubUser.first.type
SubUser Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."type" IN ('SubUser') LIMIT 1
(irb):19: warning: Object#type is deprecated; use Object#class
=> SubUser(id: integer, type: string, name: string, created_at: datetime, updated_at: datetime)
ruby-1.8.7-p352 :020 > SubUser.first.methods.grep("type")
SubUser Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."type" IN ('SubUser') LIMIT 1
=> ["type"]
ruby-1.8.7-p352 :021 > SubUser.first.methods.grep("name")
SubUser Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."type" IN ('SubUser') LIMIT 1
=> []
ruby-1.8.7-p352 :022 > SubUser.first.name
SubUser Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."type" IN ('SubUser') LIMIT 1
=> "Joe"
ruby-1.8.7-p352 :023 > SubUser.first.methods.grep("type")
SubUser Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."type" IN ('SubUser') LIMIT 1
=> ["type"]
ruby-1.8.7-p352 :024 > SubUser.first.methods.grep("name")
SubUser Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."type" IN ('SubUser') LIMIT 1
=> ["name"]

@jonleighton jonleighton was assigned Nov 19, 2011
@Fryguy

As @jrafanie says, because #type is defined on Object in Ruby 1.8.7, certain code paths won't then create the type column's attribute methods. Here is a temporary workaround that can be put into config/intializers:

if RUBY_VERSION < "1.9"
  class ActiveRecord::Base
    undef :type
  end
end
@jrafanie

@jonleighton is there an update on this? Is there anything else needed?

@jonleighton
Ruby on Rails member

This is fixed on master, I believe. I don't have time to do a backport fix and we are deprecating 1.8 support soon anyway, so I will close this. (A patch against 3-1-stable would be okay though, if someone does it.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment