Usando OpenStruct em formulários de busca no Rails
Fazer formulários que não tenha um Model diretamente associado sempre foi um problema no Rails. Isso se deve ao “Convention over configuration” e não vejo grandes problemas nisso, pois 90% dos formulários são para criação/edição de dados no Banco de Dados e, por conseqüência, utilizam um Model.
Mas e os outros 10%?
Vi artigo no blog da Plataforma sobre como resolver esse problema, porém o código parou de funcionar com o Rails 3. Para descobrir o por que disso, fui investigar no código do Rails (ahh esse mundo OpenSource) e descobri que quando você inclui por exemplo um text_field
é retornado um novo objeto da classe InstanceTag
e executa o método to_input_field_tag
.
Neste método to_input_field_tag
, que está o problema. Passou-se a verificar se na classe que está sendo chamado o form existe o método do text_field que queremos e nesse caso não existe, gerando um erro.
Para contornar isso é nessesário fazer um Monkey Patch na classe OpenStruct
modificando o método respond_to?
:
class OpenStruct
def respond_to?(symbol, include_private = false)
!ActiveRecord::Base.instance_methods.include? symbol.to_s
end
end
Assim, ele responderá a qualquer coisa menos ao aos métodos de instância que o ActiveRecord, evitando que nos passemos totalmente por um model, o que causaria outros problemas.
Além disso modifiquei o nome do helper, já que não utilizava isso apenas para buscas, e primeiro é verificado se uma variável de instância com o nome do objeto existe (@contacts
por exemplo) e caso não exista é buscado da variável params:
require 'ostruct'
module OpenFormHelper
def open_form_for(object_name, options={}, &block)
options[:html] = {:method => :get}.update(options[:html] || {})
options[:as] = object_name
object = OpenStruct.new(instance_variable_get("@#{object_name}") || params[object_name])
form_for(object, options, &block)
end
end
Fiz a modificação da variável pois em algumas buscas queria que algumas opções viessem marcadas por padrão, ou seja teria que adicioná-las a uma variável e escrever no params não é recomendável.
Lendo o código do Rails
Uma dica final que eu gostaria de deixar é que quando problemas como esse ocorrem é a melhor hora para investigar o código do Rails e tentar descobrir o que está acontecendo, ficando muito mais fácil entendermos como o Framework funciona.