This project is archived and is in readonly mode.
Collection Associations Build Method Not Supported for STI
Reported by simple10 | January 18th, 2011 @ 07:16 AM
The belongs_to association build method does not currently allow for specifying a :type subclass. This creates a lot of confusion and annoyances around STI support.
# Currently working...
u = User.first
b = u.badges << Badges::Superhero.new
# b.class == Badges::Superhero
# Not working...
u = User.first
u.badges.build(:type => Badges::Superhero)
# b.class == Badge
The quick fix is to change the build_association method in ActiveRecord::Reflection::AssociationReflection to detect if :type is a Class object and create the appropriate subclass model.
class ActiveRecord::Reflection::AssociationReflection
def build_association(*opts)
col = klass.inheritance_column.to_sym
if (h = opts.first).is_a? Hash and (type = h.symbolize_keys[col]) and type.class == Class
opts.first[col].to_s.constantize.new(*opts)
elsif klass.abstract_class?
raise "#{klass.to_s} is an abstract class and can not be directly instantiated"
else
klass.new(*opts)
end
end
end
Full writeup here: http://www.simple10.com/rails-3-sti/
Comments and changes to this ticket
-
x37v March 1st, 2011 @ 07:05 PM
This works nicely for
parent.collection.build(:type => ClassName)
but it breaksparent.collection.create(:type => ClassName)
the parent_id isn't filled in in the created object...I'm not sure why because the original source for build_association is very simple and there is also a create_association which i assume would be called for the collection.create approach..
-
x37v March 1st, 2011 @ 07:07 PM
well, besides the fact that the type field is filled in with a class instead of a string.. i figure it should do h.symbolize_keys[col] = type.to_s
-
Marc-André Lafortune May 9th, 2011 @ 09:11 PM
Got bitten by this. A solution for this problem would be nice.
-
Coutud May 21st, 2011 @ 10:26 PM
Encoutered the same issue here, and the given patch seems to be working. I'd remove the && type.class == Class, and would use ActiveRecord::Base.compute_type(options.first[col]) instead of .constantize
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>