Skip to content

Instantly share code, notes, and snippets.

@simonbaird
Created February 8, 2012 02:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simonbaird/1764629 to your computer and use it in GitHub Desktop.
Save simonbaird/1764629 to your computer and use it in GitHub Desktop.
Specify type when creating a record in AR STI
#
# This was causing problems when submitting the nested object form
# in a/v/product/channels_edit because all the nested channels would
# be created at plan Channel objects instead of the PrimaryChannel, EusChannel etc.
#
# In active record normally :type is ignored, eg:
# Channel.create(:type='PrimaryChannel', :etc=>1, ...)
# ignores the type attr and uses 'Channel'.
#
# This hack will make it actually use the :type value.
#
# Usage:
#
# class User < ActiveRecord::Base
# extend ActiveRecord::CreateWithSubtype
# ...
# end
#
# class AdminUser < User
# ...
# end
#
# >> User.create(:type=>'AdminUser', :username=>'simon', ...) #=> #<AdminUser id:123 ...>
#
# Actually needed this for nested objects in forms using accepts_nested_attributes_for.
# http://railscasts.com/episodes/197-nested-model-form-part-2
#
# When updating the type is preserved, but when creating a new subobject with the nested form
# the type is always the base class, which in my case was a problem.
#
# (I put this file in lib/active_record/create_with_subtype.rb)
#
module ActiveRecord
module CreateWithSubtype
def create(attributes=nil, &block)
# Check if :type attribute exists. Remove it from attributes
# (Note that attributes can be an array, hence Hash test)
specified_type = attributes.delete(:type) if attributes.is_a?(Hash)
if specified_type
# Find the specified class
use_sub_class = const_get(specified_type)
# Sanity check
raise "'#{use_sub_class}' not a subclass of '#{self}'" unless self.descendants.include?(use_sub_class)
# Call create on the specified subclass
use_sub_class.create(attributes, &block)
else
# Otherwise, just do the normal thing
super(attributes, &block)
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment