Pergunta

Eu tenho um formulário que me permite adicionar arquivos de formatos diferentes a um fluxo. Portanto, um fluxo é composto de muitos arquivos, esses arquivos são arquivos XML, mas basicamente têm esquemas diferentes. Eu tenho um formulário que permite ao usuário adicionar o arquivo que desejar, estou usando o STI (que funciona muito bem quando os dados já estão na tabela), meu problema é adicionar os dados à tabela.

O formulário possui 1 campo de entrada, apenas um FILE_FIELD que permite ao usuário selecionar o arquivo que deseja fazer o upload. Como tenho apenas um formulário, não sou capaz de instanciar o objeto correto, tenho que fazê -lo programaticamente .. e não tenho certeza de como fazê -lo.

Eu apenas (ou posso) adicionar uma suspensão com os tipos possíveis e chamar esse tipo de 'tipo' para que, quando o formulário seja enviado, os trilhos instanciem o tipo de gravação de objeto porque o atributo de tipo é fornecido?

Qual é a melhor prática para isso. Estou executando o Rails 2.3.4.

Foi útil?

Solução

Eu encontrei uma solução em http://coderrr.wordpress.com/2008/04/22/building-the-tlight-class-with-sti-in-lails/#comment-1826

class GenericClass < ActiveRecord::Base
  class << self
    def new_with_cast(*a, &b)
      if (h = a.first).is_a? Hash and (type = h[:type] || h['type']) and (klass = type.constantize) != self
        raise "wtF hax!!"  unless klass < self  # klass should be a descendant of us
        return klass.new(*a, &b)
      end

      new_without_cast(*a, &b)
    end
    alias_method_chain :new, :cast
  end
end

O que funcionou muito bem para mim com código mínimo - não sei se é hackish ou não, mas funciona e é bastante limpo. Gostei do fato de que suas apenas 10 linhas de código.

Outras dicas

Não sei quantos tipos você tem, mas simplesmente usei controladores e visualizações separados para os diferentes tipos no passado. Dessa forma, você não cria um novo objeto da classe base e tenta definir o tipo, basta usar o modelo que herda da classe base. Cada página nova/editar para seus recursos pode renderizar um parcial compartilhado no bloco form_for. O parcial conteria seu arquivo_field.

Dessa forma, quando o formulário for enviado, ele será para o controlador correto, chamando o recurso correto.New e tudo está ok.

A desvantagem, é claro, são mais arquivos e, qualquer que seja a página que você esteja vinculando a "Adicionar novo arquivo", você precisa adicionar vários links como "Adicionar novo esse tipo de arquivo", "Adicionar novo esse tipo de arquivo" etc.

Quanto a definir o tipo no formulário, não tenho certeza se isso funciona, duvido, mas tente (informe -nos). Você pode fazer com que esse tipo suspense um select_tag e, quando alterado, use JavaScript para alterar o local da ação no formulário.

Editado e adicionado de trabalho básico em torno

Não que eu goste dessa solução e duvido que não seja o melhor, mas se você realmente não quer controladores separados e precisa fazer isso funcionar, poderá fazer algo assim:

class XmlFile < ActiveRecord::Base
end

class XmlFileTypeA < XmlFile 
end

class XmlFileTypeB < XmlFile 
end

def create
    # Leaving this case statement in the controller for simplicity but you probably want to move this to the model
    case params[:chosen_xml_type]
      when "file_type_a"
        @item = XmlFileTypeA.new(params)
      when "file_type_b"
        @item = XmlFileTypeB.new(params)
      else
        raise "Unknown file type!"
      etc
    end
end
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top