views:

151

answers:

2

I have STI implementation as follows:

class Automobile < ActiveRecord::Base
end

class Car < Automobile
end

class Truck < Automobile
end

class User < ActiveRecord::Base
  has_many :automobiles
  accepts_nested_attributes_for :automobiles
end

I am creating a list of automobiles for a user. For each automobile, the UI sets the type field and the properties associated with the automobile.While form submission, the type field is ignored as it is a protected attribute.

How do I work around this issue? Is there a declarative way to unprotect a protected attribute?

Edit: This is my current solution for the problem: I override the attributes_protected_by_default private method in my model class.

class Automobile < ActiveRecord::Base
private
  def attributes_protected_by_default
    super - [self.class.inheritance_column]
  end
end

This removes the type field from the protected list.

I am hoping that there is a better way than this.

A: 

I would add a helper method on User that instantiates the appropriate subclass:

class User < ActiveRecord::Base
  def self.automobile_from_type(type)
    self.automobiles << case type
    when "Car"
      Car.new
    when "Truck"
      Truck.new
    else
      raise ArgumentError, "Unknown automobile type: #{type.inspect}"
    end
  end
end

Use it like this:

class AutomobilesController < ApplicationController
  def create
    @automobile = current_user.automobile_from_type(params[:automobile][:type])
    if @automobile.update_attributes(params[:automobile]) then
      redirect_to @automobile
    else
      render :action => :new
    end
  end
end

The code above is "safe": an attacker can't inject arbitrary text into your automobiles.type column. Your solution, while it works, has the disadvantage of enabling attacks.

François Beausoleil
My scenario is bit more complicated. I have three layers of nesting in my submission. I have to recreate the whole structure to perform this validation. I have resorted to adding a format validation for the `type` field in the Automobile class.
KandadaBoggu
A: 

I ended up doing this:

class Automobile < ActiveRecord::Base
private
  def attributes_protected_by_default
    super - [self.class.inheritance_column]
  end
end
KandadaBoggu