New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
nested_attributes_for does not work with STI #3749
Comments
First attempt at fixing the bug here. |
This isn't just an issue with nested_attributes - creating a model via an association directly will fail also. The reason is you don't want arbitrary data going into the type column as it could create a security hole: class User < ActiveRecord::Base; end
class Administrator < User; end
class ApplicationController < ActionController::Base
before_filter :load_site
def load_site
@site = Site.find_by_url!(request.host)
end
end
class UsersController < ApplicationController
respond_to :html, :json
def create
@user = @site.users.build(params[:user])
flash[:notice] = 'You have successfully signed up to our service' if @user.save
respond_with(@user)
end
end If Rails didn't protect both the foreign key and the type column this code would be open to all sorts of abuse. If you want to enable it on a class by class basis then the generic module below will allow you to pass a module Morphing
extend ActiveSupport::Concern
module ClassMethods
def new(attributes = {}, options = {}, &block)
prefix = base_class.name.demodulize.underscore
klass_type = attributes.delete("#{prefix}_type".to_sym)
return super if klass_type.blank?
klass_name = "#{klass_type.to_s.camelize}"
if parent.const_defined?(klass_name)
klass = parent.const_get(klass_name)
elsif parent != Object && Object.const_defined?(klass_name)
klass = Object.const_get(klass_name)
else
begin
klass = parent.const_missing(klass_name)
rescue NameError => e
if e.instance_of?(NameError)
raise ArgumentError, "Unknown #{prefix} type: #{klass_type}"
else
raise e
end
end
end
klass.new(attributes, options, &block)
end
end
end This then allows you to do the following: admin = User.new(:user_type => 'administrator') There has been a pull request for this feature before: #1686 |
Thank you for your comments! I agree that allowing the Let's look at the Furthermore, I think that not having uniform behavior is more dangerous, because people will Google for the issue, land on one of the blog posts that I mentioned in my bug report, and apply the fix, without thinking of security. If we have a simple, uniform conceptual model, we have more time and energy to think about security. Thank you for your time and consideration! |
When using the *_attributes= method generated by
nested_attributes_for
to create new models the newly created models always have the base class. Thetype
attribute is ignored.Failing test case against master:
pwnall@344cddb
Branch containing the failing test case:
https://github.com/pwnall/rails/tree/nested_attrs_sti
I'll try to work on a fix. In the meantime, I hope this can help others experiencing this problem.
The bug seems to be well-known, but I couldn't find any proposed fixes.
http://grosser.it/2010/06/04/fixing-rails-nested-attributes-on-collections-with-sti/
http://stackoverflow.com/questions/2553931/can-nested-attributes-be-used-in-combination-with-inheritance
http://coderrr.wordpress.com/2008/04/22/building-the-right-class-with-sti-in-rails/
The text was updated successfully, but these errors were encountered: