Nested form not saving in rails 3.1 - ruby-on-rails

Noob question, I'm sure, but I can't seem to find my mistake. SymptomSets are saving w/ the proper user_id, but the nested symptoms disappear. Note that the user model structure is identical to that in the Rails Tutorial (save that it has_many :symptom_sets)
Models:
class SymptomSet < ActiveRecord::Base
attr_accessible :symptoms, :symptoms_attributes
belongs_to :user
has_many :symptoms, :dependent => :destroy
accepts_nested_attributes_for :symptoms, allow_destroy: true
end
class Symptom < ActiveRecord::Base
attr_accessible :name, :duration, :symptom_set_id
belongs_to :symptom_set
end
Controller:
class SymptomSetsController < ApplicationController
before_filter :signed_in_user, only: [:create, :new]
def new
#symptom_set = SymptomSet.new
3.times do
symptom = #symptom_set.symptoms.build
end
end
def create
#symptom_set = current_user.symptom_sets.build(params[:symptom_sets])
if #symptom_set.save
flash[:success] = "Symptoms submitted!"
redirect_to root_url
else
render 'static_pages/home'
end
end
And the View:
<%= simple_form_for #symptom_set, :html => { :class => 'form-inline' } do |f| %>
<%= f.fields_for :symptoms do |builder| %>
<%= render 'symptom_fields', f: builder %>
<% end %>
<div class="actions"><%= f.submit %></div>
<% end %>
And the partial:
<%= f.input :name,
:collection=> ["Cough", "Fever", "Headache", "Lethargy"],
label: "Symptom",
prompt: "Select a symptom",
:input_html => { :class => "span3" }%>
<%= f.input :duration,
:collection => 1..14,
label: "Duration",
prompt: "How many days?" %>
finally, the rails server console outputs the following:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"s7ksuk40M2r76Nq4PGEEpTpkCECxFniP4TtpfSHszQk=", "symptom_set"=>{"symptoms_attributes"=>{"0"=>{"name"=>"Cough", "_destroy"=>"false", "duration"=>"2"}, "1
"=>{"name"=>"Fever", "_destroy"=>"false", "duration"=>"2"}, "2"=>{"name"=>"", "_destroy"=>"1", "duration"=>""}}}, "commit"=>"Create Symptom set"}
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."remember_token" ='OH6_nuvySNjd6AbTuDunsw' LIMIT 1
(0.1ms) BEGIN
SQL (0.4ms) INSERT INTO "symptom_sets" ("created_at", "updated_at", "user_id") VALUES ($1, $2, $3)
RETURNING "id" [["created_at", Tue, 05 Feb 2013 21:12:07 UTC +00:00], ["updated_at", Tue, 05 Feb 20
13 21:12:07 UTC +00:00], ["user_id", 1]]
(1.1ms) COMMIT

I'd try changing:
#symptom_set = current_user.symptom_sets.build(params[:symptom_sets])
to:
#symptom_set = current_user.symptom_sets.new(params[:symptom_sets])
I don't know if build would work there.
And also checking the params on the terminal log if it is called symptom_sets and if it's sending the parameters of nested form attributes.
EDIT:
I Really think your param's name would be symptom_set in singular. check that.

Related

RAILS 3.2 - Submit form posts "nil" variable using params

I'm stuck on something that doesn't make sense! I'm simply trying to submit a form with "comments" on a blog post.
Here is my form view:
<%= form_for #comment, :remote => true, :url => forumpost_comments_path(forumpost) do |s| %>
<div class="field">
<%= s.label :content, "Write a comment" %>
<%= s.text_area :content, :rows => "3" %>
</div>
<%= s.submit "Reply"%>
<% end %>
Here is my controller:
def create
#forumpost = Forumpost.find_by_id(params[:forumpost_id])
#comment = #forumpost.comments.build(params[:comment])
#comment.user_id = current_user.id
if #comment.save
redirect_to search_static_pages_path
else
redirect_to search_static_pages_path
end
end
Here is my model:
class Comment < ActiveRecord::Base
attr_accessible :content
belongs_to :user
belongs_to :forumpost
validates :user_id, presence: true
validates :forumpost_id, presence: true
end
And here are my logs:
Started POST "/forumposts/331/comments" for 127.0.0.1 at 2013-12-14 11:41:24 -0800
Processing by CommentsController#create as JS
Parameters: {"utf8"=>"✓", "authenticity_token"=>"3w3WACRYA6JEwvIg9C66k+cR1ZdRSWwA5Z+W0et1sS8=",
"forumpost"=>{"content"=>"test"}, "commit"=>"Reply", "forumpost_id"=>"331"}
(0.1ms) begin transaction
SQL (0.8ms) INSERT INTO "comments" ("content", "created_at", "forumpost_id", "updated_at", "user_id")
VALUES (?, ?, ?, ?, ?) [["content", nil], ["created_at", Sat, 14 Dec 2013 18:58:58 UTC +00:00],
["forumpost_id", 331], ["updated_at", Sat, 14 Dec 2013 18:58:58 UTC +00:00], ["user_id", 1]]
(14.3ms) commit transaction
As you can see, the content portion is nil even though I have filled out the content field and submitted it.
I would really appreciate any guidance on the matter! Thanks!

Rails 4, double-nested models and strong parameters

I am fairly new to Ruby on Rails and began with rails 4 right away.
I have sucessfully nested a Recipe and a Ingredient model so that they can be added in the same form. Next I want to nest quantity within ingredient so that that aswell can be added within the same form. Everything seems to be working fine up until when the quantity of the ingredient is about to be inserted in the database and from this i believe there is something wrong with the strong params in the recipes_controller. But i will post the full code below.
I am using simple_form for the forms.
Thankful for any help!
Here are my models:
class Recipe < ActiveRecord::Base
has_many :comments, dependent: :destroy
has_many :ingredients, dependent: :destroy
accepts_nested_attributes_for :ingredients, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
validates :title, presence: true
validates :desc, presence: true
end
class Ingredient < ActiveRecord::Base
belongs_to :recipe
has_many :quantities, dependent: :destroy
accepts_nested_attributes_for :quantities, :reject_if => lambda { |a| a[:name].blank? }, :allow_destroy => true
end
class Quantity < ActiveRecord::Base
belongs_to :ingredient
end
Here is the recipes_controller
class RecipesController < ApplicationController
def new
#recipe = Recipe.new
3.times do
ingredient = #recipe.ingredients.build
1.times {ingredient.quantities.build }
end
end
def create
#recipe = Recipe.new(params[:recipe].permit(:title, :desc, ingredients_attributes: [:id, :recipe_id, :name, :_destroy, quantities_attributes: [:id, :ingredient_id, :amount, :unit, :_destroy]]))
if #recipe.save
redirect_to #recipe
else
render "new"
end
end
def show
#recipe = Recipe.find(params[:id])
end
def edit
#recipe = Recipe.find(params[:id])
end
def update
#recipe = Recipe.find(params[:id])
if #recipe.update(params[:recipe].permit(:title, :desc))
redirect_to #recipe
else
render 'edit'
end
end
def destroy
#recipe = Recipe.find(params[:id])
#recipe.destroy
redirect_to recipes_path
end
def index
#recipes = Recipe.all
end
private
def post_params
params.require(:recipe).permit(:title, :desc, ingredients_attributes: [:id, :recipe_id, :name, :_destroy, quantities_attributes: [:id, :ingredient_id, :amount, :unit, :_destroy]])
end
end
Then i use simple form to create a form for recipe, ingredient and quantity through partials.
_form:
<%= simple_form_for #recipe do |f| %>
<%= f.error_notification %>
<%= f.input :title %>
<%= f.input :desc %>
<%= f.simple_fields_for :ingredients do |builder| %>
<%= render "ingredient_fields", :f => builder %>
<% end %>
<p class="links">
<%= link_to_add_association 'add ingredient', f, :ingredients %>
<p class="links">
<%= f.error :base%>
<%= f.submit %>
<% end %>
Which renders from _ingredients_fields:
<div class="nested-fields">
<%= f.input :name, label: "Ingredient" %>
<%= f.simple_fields_for :quantities do |builder| %>
<%= render "quantities_fields", :f => builder %>
<% end %>
<%= link_to_remove_association "remove", f %>
</div>
which renders from _quantities_fields: [EDITED]
<div class="nested-fields">
<%= f.input :amount %>
<%= f.input :unit %>
</div>
Trying to add new recipes result in the following log statement:
Started POST "/recipes" for 127.0.0.1 at 2013-10-29 14:15:40 +0100
Processing by RecipesController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"t6LKgDLwAxaU9xo2ipyCM+j1yfVF9WrI8AoGTX+gRkw=", "recipe"=>{"title"=>"Pancakes", "desc"=>"Tasty", "ingredients_attributes"=>{"0"=>{"name"=>"Milk", "quantities_attributes"=>{"0"=>{"amount"=>"1", "unit"=>"Cup"}}, "_destroy"=>"false"}}}, "commit"=>"Create Recipe"}
[1m[35m (0.1ms)[0m begin transaction
[1m[36mSQL (3.5ms)[0m [1mINSERT INTO "recipes" ("created_at", "desc", "title", "updated_at") VALUES (?, ?, ?, ?)[0m [["created_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00], ["desc", "Tasty"], ["title", "Pancakes"], ["updated_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00]]
[1m[35mSQL (0.4ms)[0m INSERT INTO "ingredients" ("created_at", "name", "recipe_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00], ["name", "Milk"], ["recipe_id", 27], ["updated_at", Tue, 29 Oct 2013 13:15:40 UTC +00:00]]
[1m[36m (7.8ms)[0m [1mcommit transaction[0m
Redirected to http://www.projectcookbook.dev/recipes/27
Completed 302 Found in 22ms (ActiveRecord: 11.7ms)
You're using similar render for _quantities and _ingredients partials, which is wrong. In _quantities_field you don't need
<%= f.simple_fields_for :quantities do |builder| %>
<%= render "quantities_fields", :f => builder %>
<% end %>
AND should adjust
<%= f.input :name, label: "Quantity" %>
in _quantities_fields.
UPD
I think the problem is in :reject_if-clause at Ingredient model. It should be
:reject_if => lambda { |a| a[:amount].blank? }
bc here you specify conditions for Quantity, not for Ingredient
On code styling:
1) In controller it's better to use relevant name of private method for strong parameters: recipe_params instead of post_params and then use it for creation of new Recipe #recipe = Recipe.new(recipe_params)
2) Current associations between Recipe, Ingredient and Quantity will lead to Ingredient duplication in case two Recipes use similar one. The reason is belongs_to, which define single association. Try another approach (bellow).
BTW. recently I've answered on the similar question. Check it out: How do I reference an existing instance of a model in a nested Rails form?
I thing you are missing in this part
<%= simple_form_for #recipe do |f| %>
it should be
<%= simple_nested_form_for #recipe do |f| %>

Rails and ancestry - form submits 'parent_id' empty

I've followed Railscast episode #262 tutorial on ancestry. But when I submit my form, the rails server log says that parent_id is empty:
rails server log:
Started POST "/posts/1/comments" for 127.0.0.1 at 2013-09-26 16:14:59 +0200
Processing by CommentsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"9+9U/etsazbrJxwWah/eRD9v3fKBnjpy+y5s+g7N/Bw=", "comment"=>{"parent_id"=>"", "author"=>"some name", "author_email"=>"mail#domain.com", "author_url"=>"", "content"=>"banane"}, "commit"=>"Post Comment", "post_id"=>"1"}
Post Load (0.1ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT 1 [["id", "1"]]
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "comments" ("author", "author_email", "author_url", "content", "created_at", "post_id", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?) [["author", "some name"], ["author_email", "mail#domain.com"], ["author_url", ""], ["content", "banane"], ["created_at", Thu, 26 Sep 2013 14:14:59 UTC +00:00], ["post_id", 1], ["updated_at", Thu, 26 Sep 2013 14:14:59 UTC +00:00]]
(38.6ms) commit transaction
(0.1ms) begin transaction
(0.1ms) commit transaction
Redirected to http://0.0.0.0:3000/posts/1
Completed 302 Found in 49ms (ActiveRecord: 39.4ms)
comments_controller.rb:
def new
#comment = Comment.new
#comment.parent_id=params[:parent_id]
end
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(params[:comment].permit(:author, :author_email, :author_url, :content, :parent_id))
respond_to do |format|
if #comment.save
stuff
else
other stuff
end
end
end
def comment_params
params.require(:comment).permit(...some stuff..., :parent_id)
end
comment.rb:
class Comment < ActiveRecord::Base
belongs_to :post
has_ancestry
end
post.rb:
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments, :dependent => :destroy
accepts_nested_attributes_for :comments
end
views/posts/show.html.erb:
<% #post.comments.each do |comment| %>
<%= show some stuff %>
<%= link_to (post_path(:anchor => "respond", :parent_id => comment)) do%>
<%= "Reply"%>
<% end %>
<% end %>
<%= render 'comments/comment_form'%>
_comment_form.html.erb:
<%= form_for [#post, #post.comments.build], html: { :id => "commentform"} do |f| %>
<%= f.hidden_field :parent_id %>
<%= some fields %>
<%= f.submit "Post Comment"%>
Rails debug info:
--- !ruby/hash:ActionController::Parameters
parent_id: '17'
action: show
controller: posts
id: '1'
I guess somethings wrong with my create method in the CommentsController, but I can't figure out what's missing. So, I got this working. I was submitting the form from my posts/show view, so I had to call #comment = Comment.new(:parent_id => params[:parent_id]) in the show action of the post-controller as well.
If you are using Rails >3.0.0 try this in your comments controller:
#comment = Comment.new
#comment.parent_id=params[:parent_id]
instead of
#comment = Comment.new(:parent_id => params[:parent_id])
Add :parent_id to comment_params in the comments controller.

Nested resource wont create data, rollback transaction right after begin transaction

My problem is that a tag wont be created which is nested in posts.
I have Post which have tags nested in them. Like this
resources :posts do
resources :tags, :only => [:new, :create, :destroy]
end
In my tags controller i have this
class TagsController < ApplicationController
before_filter :authenticate_user!
def new
#post = Post.find(params[:post_id])
#tag = Tag.new
end
def create
#post = Post.find(params[:post_id])
#tag = #post.tags.build(params[:tags])
if #tag.save
flash[:notice] = "Tag created"
redirect_to #tag.post
else
flash[:error] = "Could not add tag at this time"
redirect_to #tag.post
end
end
end
new.html.erb
<%= form_for [#post, #tag] do |f| %>
<% if #tag.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#tag.errors.count, "error") %> prohibited this tag from being saved:</h2>
<ul>
<% #tag.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.text_field :tagable_type, :placeholder => "Type" %>
</div>
<div class="field">
<%= f.text_field :tagable_id, :placeholder => "Id" %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Tag model
class Tag < ActiveRecord::Base
attr_accessible :post_id, :user_id, :tagable_type, :tagable_id
validates :post_id, presence: true
belongs_to :tagable, :polymorphic => true
belongs_to :post
belongs_to :user
end
Post model
class Post < ActiveRecord::Base
attr_accessible :body, :link, :thumbnail, :title, :user_id, :youtube, :youtube_id, :website_name, :image_field
default_scope order: 'posts.active DESC'
has_many :tags, :dependent => :destroy
has_many :comments, :as => :commentable, :dependent => :destroy
belongs_to :user
end
UPDATE:
Now i can create a tag but the tagable_type and tagable_id fields are not being created for some reaseon
Started POST "/posts/18/tags" for 127.0.0.1 at 2013-06-26 15:54:14 +0200
Processing by TagsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"gwpTs0Qqcrre4tH974RrfpaENGZKtSbkJx2U0H67AcM=", "tag"=>{"tagable_type"=>"Player", "tagable_id"=>"2"}, "commit"=>"Create Tag", "post_id"=>"18"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Post Load (0.1ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? ORDER BY posts.active DESC LIMIT 1 [["id", "18"]]
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "tags" ("created_at", "post_id", "tagable_id", "tagable_type", "updated_at", "user_id") VALUES (?, ?, ?, ?, ?, ?) [["created_at", Wed, 26 Jun 2013 13:54:14 UTC +00:00], ["post_id", 18], ["tagable_id", nil], ["tagable_type", nil], ["updated_at", Wed, 26 Jun 2013 13:54:14 UTC +00:00], ["user_id", 1]]
(6.9ms) commit transaction
Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = 18 ORDER BY posts.active DESC LIMIT 1
Redirected to http://localhost:3000/posts/18
Completed 302 Found in 15ms (ActiveRecord: 7.9ms)
There is a typo in the create() action of your TagsController:
#tag = #post.tags.build(params[:tags])
The hash used to create the tag should be params[:tag], not params[:tags].

Fields_for has_many associations not saving

So I have a deeply nested association among Polls, Questions, and Answers:
class Poll < ActiveRecord::Base
attr_accessible :description, :end_time, :start_time, :title, :user_id, :questions_attributes, :is_live
belongs_to :user
has_many :questions, :dependent => :destroy
# This is the plularized form of sms, it's not smss
has_many :sms, :through => :questions
has_many :feedbacks
accepts_nested_attributes_for :questions, :reject_if => lambda { |a| a[:content].blank?}, :allow_destroy => true
end
class Question < ActiveRecord::Base
attr_accessible :poll_id, :title, :answer_attributes
belongs_to :poll
has_many :answers, :dependent => :destroy
# THis is the plularized form of sms, it's not smss
has_many :sms
#If someone creates a form with a blank question field at the end, this will prevent it from being rendered on teh show page
accepts_nested_attributes_for :answers, :reject_if => lambda { |a| a[:content].blank?}, :allow_destroy => true
end
class Answer < ActiveRecord::Base
attr_accessible :is_correct, :question_id, :title
belongs_to :question
end
And am trying to save all objects in a single fields_for form like so.
= form_for #poll, :class=>'create-poll-form' do |f|
= f.text_field :title, :autofocus => true, :placeholder => "Poll Title"
= f.text_field :description, :placeholder => 'Description'
= f.fields_for :questions do |builder|
= render "questions/question_fields", :f => builder
= f.submit "Create Poll", :class => 'btn btn-danger'
Questions Partials
%p
= f.label :title, "Question"
= f.text_field :title
= f.check_box :_destroy
= f.label :_destroy, "Remove Question"
%p
= f.fields_for :answers do |builder|
= render "answers/answer_fields", :f => builder
Answers Partial
%p
= f.label :title, "Answer"
= f.text_field :title
= f.check_box :_destroy
= f.label :_destroy, "Remove Answer"
Yet the PollsController isn't persisting the data:
def create
binding.pry
#poll = current_user.polls.new(params[:poll])
# #poll = Poll.create(params[:poll])
binding.pry
#poll.save!
redirect_to root_path
end
def new
#poll = Poll.new
1.times do
question = #poll.questions.build
2.times {question.answers.build}
end
end
Any tips here would be amazing, I've been working on this for a bit and it's stumping me! Thanks in advance!
Also here's the server log:
Started POST "/polls" for 127.0.0.1 at 2013-06-06 20:14:47 -0400
Processing by PollsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"hk+KuNsTLx3sH9pE7Mf8XETGsmxTsRN4/tWUBn3CIVE=", "poll"=>{"title"=>"Testing 1-2-1-2", "description"=>"Up on the mic", "questions_attributes"=>{"0"=>{"title"=>"Cake or Death?", "_destroy"=>"0", "answers_attributes"=>{"0"=>{"title"=>"Cake", "_destroy"=>"0"}, "1"=>{"title"=>"Death", "_destroy"=>"0"}}}}}, "commit"=>"Create Poll"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Question Load (0.5ms) SELECT "questions".* FROM "questions" WHERE "questions"."poll_id" IS NULL
(0.3ms) BEGIN
SQL (47.6ms) INSERT INTO "polls" ("created_at", "description", "end_time", "is_live", "start_time", "title", "updated_at", "user_id") VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING "id" [["created_at", Fri, 07 Jun 2013 00:16:46 UTC +00:00], ["description", "Up on the mic"], ["end_time", nil], ["is_live", nil], ["start_time", nil], ["title", "Testing 1-2-1-2"], ["updated_at", Fri, 07 Jun 2013 00:16:46 UTC +00:00], ["user_id", 1]]
(0.8ms) COMMIT
Redirected to http://localhost:3000/
Completed 302 Found in 170668ms (ActiveRecord: 54.9ms)
I'm not sure if this is the problem but in your
class Question < ActiveRecord::Base
attr_accessible :poll_id, :title, :answer_attributes
but in your log file it has
Parameters: {"utf8"=>"✓", "authenticity_token"=>"hk+KuNsTLx3sH9pE7Mf8XETGsmxTsRN4/tWUBn3CIVE=", "poll"=>{"title"=>"Testing 1-2-1-2", "description"=>"Up on the mic", "questions_attributes"=>{"0"=>{"title"=>"Cake or Death?", "_destroy"=>"0", "answers_attributes"=>{"0"=>{"title"=>"Cake", "_destroy"=>"0"}, "1"=>{"title"=>"Death", "_destroy"=>"0"}}}}}, "commit"=>"Create Poll"}
The difference being :answers_attributes, rather than :answer_attributes i.e. answer vs answer*s
This may be causing the data to be thrown away.

Resources