Como substituir o att_protected?
-
22-09-2019 - |
Pergunta
Eu tenho a implementação do STI da seguinte maneira:
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
Estou criando uma lista de automóveis para um usuário. Para cada automóvel, a interface do usuário define o type
campo e as propriedades associadas ao automóvel. type
O campo é ignorado, pois é um atributo protegido.
Como faço para trabalhar em torno desse problema? Existe uma maneira declarativa de unprotect
um atributo protegido?
Editar:Esta é a minha solução atual para o problema: substituo o attributes_protected_by_default
Método privado na minha aula de modelo.
class Automobile < ActiveRecord::Base
private
def attributes_protected_by_default
super - [self.class.inheritance_column]
end
end
Isso remove o type
campo da lista protegida.
Espero que haja uma maneira melhor do que isso.
Solução
Acabei fazendo isso:
class Automobile < ActiveRecord::Base
private
def attributes_protected_by_default
super - [self.class.inheritance_column]
end
end
Outras dicas
Eu adicionaria um método auxiliar no usuário que instancia a subclasse apropriada:
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 assim:
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
O código acima é "seguro": um invasor não pode injetar texto arbitrário na coluna Automobiles.Type. Sua solução, enquanto funciona, tem a desvantagem de permitir ataques.