I'm making a recipe-manager (who isn't as their first app?) in Rails, and here is my layout:
Ingredient belongs to Recipe
Recipe has many Ingredients
What is the best way to make a form that reflects this relationship? I was thinking an input that, when one is filled, creates another, so there is always 'one more' at the end of the form for ingredients.
Once I have the UI made, what would the structure of the model and controller look like? Right now I have the scaffolded controller create
method:
def create
@recipe = Recipe.new(params[:recipe])
respond_to do |format|
if @recipe.save
format.html { redirect_to(recipes_path, :notice => 'You made a new recipe!') }
format.xml { render :xml => @recipe, :status => :created, :location => @recipe }
else
format.html { render :action => "new" }
format.xml { render :xml => @recipe.errors, :status => :unprocessable_entity }
end
end开发者_JAVA技巧
end
Should the params[:recipe]
just be a more deeply nested object/hash/dictionary, that contains an array of ingredients or something?
Thanks for any guidance here.
You should use accepts_nested_attributes
here.
Some links:
API:
http://apidock.com/rails/ActiveRecord/NestedAttributes/ClassMethods/accepts_nested_attributes_for
Screencasts:
http://railscasts.com/episodes/196-nested-model-form-part-1
http://railscasts.com/episodes/197-nested-model-form-part-2
So your model will look like this
class Recipie < ActiveRecord::Base
has_many :ingredients
accepts_nested_attributes_for :ingridients, :allow_destroy => true
end
Views:
<%= form_for @recipe do |f| %>
... # reciepe fields
<%= f.fields_for :ingridients do |i| %>
... # your ingridients forms
<% end %>
...
<% end %>
And controller
def create
@recipe = Recipe.new(params[:recipe])
@recipe.save # some save processing
end
Just add ingredients by comma delimited.
This can be a text_field_tag
because you will need to parse it and save each word spaced by a comma with a before save.
class Recipie < ActiveRecord::Base
has_many :ingredients
before_save :add_ingredients
attr_accessor :ingredients_to_parse #this will be the text_field_tag
def add_ingredients
#create an array of ingredients from #ingredients_to_parse
#then loop through that array i.e. you have your ingredients_array
ingredients_array.each do
Ingredient.create(:recipe => self, :other_params => 'stuff')
end
#there are a lot of ways, I just used create to show you how to add it
end
end
So then in your form just have that text_field_tag
<%= form_for(@recipe) do |f| %>
<% f.text_field :name %>
<% text_field_tag :ingredients_to_parse %>
<%= f.submit %>
<% end %>
Then you can add Javascript so that each time a comma is added in that text_field_tag
you can just use some js to to so fancy stuff.
This way it will work when servers are slow, js is not working well, etc. It's always a good idea to get the HTML version going first too.
Good luck, let me know if you have questions/problems.
精彩评论