I've been stuck for some time on how to create a deeply nested form using formtastic in ActiveAdmin. Here's a sample of my model structure:
class Herb < ActiveRecord::Base
has_one :medicinal
attr_accessible :medicinal_attributes
accepts_nested_attributes_for :medicinal
A Herb has one Medicinal (use)
class Medicinal < ActiveRecord::Base
attr_accessible :recipe_attributes
belongs_to :herb
has_and_belongs_to_many :recipes
accepts_nested_attributes_for :recipes
A Medicinal (use) can have many Recipes
class Recipe < ActiveRecord::Base
has_and_belongs_to_many :medicinals
has_many :recipe_ingredients
has_many :ingredients, :through => :recipe_ingredients
attr_accessible :recipe_ingredients_attributes
accepts_nested_attributes_for :recipe_ingredients
And a Recipe can have many Ingredients (through recipe_ingredients)
class RecipeIngredient < ActiveRecord::Base
attr_accessible :ingredient_attributes
belongs_to :recipe
belongs_to :ingredient
Ingredient
class Ingredient < ActiveRecord::Base
attr_accessible :item
has_many :recipes, :through => :recipe_ingredients
So here's my problem. I want the user, from the Herb Entry page in ActiveAdmin, to be able to create a recipe, to be able to have the Herb AUTOMATICALLY be entered as an ingredient, and if the user enters an ingredient that doesn't currently exist, to have it entered as a NEW ingredient (so other recipes can use it). I don't think I understand how to use the contoller in ActiveAdmin well enough to know where to begin... Here's what I have so far:
ActiveAdmin.register Herb do
controller do
def new
@herb = Herb.new
@herb.build_medicinal
end
def edit
@herb = Herb.find(params[:id])
if @herb.medicinal.blank?
@herb.build_medicinal
end
end
end
form do |f|
f.inputs "Herb" do
f.inputs :name => "Medicinal", :for => :medicinal do |med|
med.input :content, :label => "Medicinal Uses", :required => true
med.has_many :recipes do |r|
r.inputs "Recipe" do
r.has_many :recipe_ingredients do |i|
i.inputs "Ingredients" do
i.input :ingredient
end
end
end
end
end
end
f.actions
end
I know this is long, but any advice you could give me would be greatly appreciated. I'm rather new to rails. Thanks!
If I were building the same site I might move the structure of the files around slightly to get the result you are looking for.
app/admin/herb.rb
ActiveAdmin.register Herb do
end
That should be all you need to create the page in active_admin. Then for your app/controller/herb_controller.rb
class HerbController < ApplicationController
def new
@herb = Herb.new
end
end
I would now check to verify you can go to ActiveAdmin and create a new herb. I would further add to your app/controller/herb_controller.rb to check to see if a new ingredient needs to be added when you create your herb.
...
def create
@herb = Herb.new
if @herb.save
@herb.create_ingredient_if_not_existing
# perform any other actions, such as flash message or redirect
else
# perform action if save not successful
end
end
Now you want to create the method within your Herb model
def create_if_not_existing
unless Ingredient.where("name = ?", self.name) then
new_ingredient = ingredient.build
new_ingredient.name = self.name
# add extra attributes here if necessary
new_ingredient.save
end
end
You can then make sure you aren't creating duplicates in either of your models with a line similar to this:
validates :name, :uniqueness => true
This is my first answer on Stack Overflow, so let me know if this was of any help to you! I struggled with the same stuff not too long ago and was lucky enough to have a couple of people help me out along the way.