ActiveAdmin vs Modelos Aninhados vs Formtastic vs Atos como Relação

Cenário

Então, vamos definir o cenário. Você está usando Atos como Relação porque permite que você defina herança dentro de seus modelos, no meu caso eu tinha uma Apresentação que estava estendendo um Recurso

# app/models/presentation.rb
class Presentation < ActiveRecord::Base
acts_as
:resource
attr_accessible
:markup
end

# app/models/resource.rb
class Resource < ActiveRecord::Base
acts_as_superclass


belongs_to
:topic
belongs_to
:level

attr_accessible
:name, :topic, :level
end

Você também notará que um Recurso tem um Tópico e um Nível ao qual pertence.

# app/models/topic.rb
class Topic < ActiveRecord::Base
attr_accessible
:name
has_many
:resources
end

# app/models/level.rb
class Level < ActiveRecord::Base
attr_accessible
:name
has_many
:resources
end

Por fim, queremos que tudo isso funcione bem com a incrível gem ActiveAdmin , que cria uma interface de administração adorável para quaisquer modelos que você definir. Neste caso, eu queria ter uma seção ‘Apresentação’ onde pudesse criar uma Apresentação com um nome , definir seu nível e tópico a partir das listas suspensas dos registros disponíveis atualmente para esses dois tipos e, finalmente, escrever alguma marcação . Portanto, há coisas vindo de vários modelos diferentes, para a mesma tela, e no caso do ActiveAdmin , isso significa trabalhar com Formtastic . A primeira coisa que você precisa fazer é gerar seu modelo ActiveAdmin

rails generate active_admin:resource Presentation

Se você então pular para a sua área de administração, verá que ela criou uma seção de Apresentação , mas atualmente contém apenas o campo de marcação que vem diretamente do modelo de Apresentação . Adicionar o nome do modelo de recursos é bastante simples, você só precisa adicioná-lo, pois ele não foi selecionado pelo gerador ActiveAdmin .

# app/admin/presentations.rb
ActiveAdmin.register Presentation do
form
do |f|
f
.inputs do
f
.input :name
f
.input :markup
end
f
.buttons
end
end

Portanto, agora queremos adicionar os seletores de nível e tópico , que devem incluir todas as entradas possíveis em seus respectivos modelos. Felizmente, o Formtastic tem uma maneira bastante boa de fazer isso em uma única linha para cada modelo

# app/admin/presentations.rb
...
f
.input :name
f
.input :level, :as => :select, :collection => Level.all, :include_blank => false, :selected => (presentation.level.id if !presentation.level.nil?)
f
.input :topic, :as => :select, :collection => Topic.all, :include_blank => false, :selected => (presentation.topic.id if !presentation.topic.nil?)

f
.input :markup
...

Se você tentar o formulário neste ponto, provavelmente descobrirá que obtém um erro ActiveRecord :: AssociationTypeMismatch , e isso se resume ao Formtastic usando a referência de nível e id de tópico no formulário. Para consertar isso, você precisa realmente ir para o controlador do ActiveAdmin e modificar seu método de criação , novamente, felizmente, bastante simples. Neste ponto, também adicionarei a função de índice do ActiveAdmin para que possamos ver os campos corretos no índice também:

ActiveAdmin.register Presentation do
form
do |f|
f
.inputs do
f
.input :name
f
.input :level, :as => :select, :collection => Level.all, :include_blank => false, :selected => (presentation.level.id if !presentation.level.nil?)
f
.input :topic, :as => :select, :collection => Topic.all, :include_blank => false, :selected => (presentation.topic.id if !presentation.topic.nil?)

f
.input :markup
end
f
.buttons
end
index
do
column
:name
column
:level
column
:topic
column
:markup
default_actions

end
controller
do
def create
@level = Level.find(params[:presentation][:level])
@topic = Topic.find(params[:presentation][:topic])
params[:presentation][:level] = @level
params[:presentation][:topic] = @topic
@presentation = Presentation.new(params[:presentation])
super
end
end
end

E isso basta! Embora pareça bastante complicado, na verdade representa uma base bastante complexa e facilmente extensível para criar muitos modelos diferentes feitos dos mesmos bits.