I have a triple nested form where a Form has many questions and questions have many answers. I have each form rendering on the show page with the form title and the form questions and input fields to create new answers associated with the asked question. The association is linking up nicely, however I cant seem to get the answers to insert into the db. I feel like it is something real easy but I cant seem to figure it out.
-Form-
<%= simple_form_for #form do |f| %>
<%= f.error_notification %>
<h1><%= #form.name %></h1>
<div class="fields">
<%= f.simple_fields_for :form_questions do |q| %>
<%= label_tag q.index+1 %>
<%= q.simple_fields_for :form_answers, q.object.form_answers.build do |a| %>
<%= a.input :answer, label: false %>
<% end %>
<% end %>
</div>
<div class="fields">
<%= f.button :submit, :class => "button", value: 'Submit' %>
</div>
<% end %>
-Form Controller-
class FormsController < ApplicationController
def new
#form = Form.new
#form.form_questions.form_answers.build
end
def create
#form = Form.new(form_params)
end
def index
#forms = Form.includes(:form_questions).all
end
def show
#form = Form.find(params[:id])
end
def edit
#form = Form.find(params[:id])
end
def form_params
params.require(:form).permit(:id, :name, form_questions_attributes: [:title, form_answers_attributes: [:answer]])
end
end
-Form Answer Controller (although if the associations are correct I feel like I should be able to handle everything in the forms controller)
class FormAnswersController < ApplicationController
def new
#form_answer = FormAnswer.new
end
def create
#form_answer = FormAnswer.new(form_answer_params)
if #form_answer.save
RequestMailer.request_submit(#form).deliver
else
format.html {render action: 'new'}
end
end
def form_answers_params
params.require(:form_answer).permit(:form_id, :form_question_id, :id, :answer)
end
end
-Server Logs-
Started PATCH "/forms/12" for 127.0.0.1 at 2014-08-05 13:31:44 -0400
Processing by FormsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"CcaCGjdoYPH2Boi1prIFhG+h5YuPHQvAxMp1dcKvWr8=", "form"=>{"form_questions_attributes"=>{"0"=>{"form_answers_attributes"=>{"0"=>{"answer"=>"hey"}}, "id"=>"50"}, "1"=>{"form_answers_attributes"=>{"0"=>{"answer"=>"ya"}}, "id"=>"51"}, "2"=>{"form_answers_attributes"=>{"0"=>{"answer"=>"go"}}, "id"=>"52"}}}, "commit"=>"Submit", "id"=>"12"}
Rendered forms/update.html.erb within layouts/application (0.1ms)
Completed 200 OK in 12ms (Views: 11.4ms | ActiveRecord: 0.0ms)
Related
I'm on week two of this issue and have recently used the railsCast #196 (revised). I know this is older - maybe that's my issue. As an extra spin I'm hosting my rails server off Cloud 9.
I've tried following a few different tutorials just to get one going & this is as far as I've gotten. The weird part is none of their syntex matches what the official ruby on rails documentation has ... Rails View templates.
In the railsCast the guy is able to get blank fields to show up ... I'm not sure how...so I haven't managed to populate the question or answer fields yet. I'm not even sure what the two rails console messages mean - besides there aren't records there to be had.
Thanks for reading & any suggestions!
-M
Without further ado, my senario ... nested forms via templates as shown in railsCast 196 ...
My rails console ...
2.2.1 :045 > cc = Survey.first.questions.first
Survey Load (0.5ms) SELECT "surveys".* FROM "surveys" ORDER BY "surveys"."id" ASC LIMIT 1
Question Load (0.2ms) SELECT "questions".* FROM "questions" WHERE "questions"."survey_id" = ? ORDER BY "questions"."id" ASC LIMIT 1 [["survey_id", 1]]
=> nil
2.2.1 :046 > cc = Survey.first.questions
Survey Load (0.3ms) SELECT "surveys".* FROM "surveys" ORDER BY "surveys"."id" ASC LIMIT 1
Question Load (0.2ms) SELECT "questions".* FROM "questions" WHERE "questions"."survey_id" = ? [["survey_id", 1]]
=> #<ActiveRecord::Associations::CollectionProxy []>
My terminal console log ...
Started GET "/surveys/5/edit" for 68.54.21.200 at 2015-11-27 02:46:48 +0000
Cannot render console from 68.54.21.200! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by SurveysController#edit as HTML
Parameters: {"id"=>"5"}
Survey Load (0.4ms) SELECT "surveys".* FROM "surveys" WHERE "surveys"."id" = ? LIMIT 1 [["id", 5]]
Question Load (0.2ms) SELECT "questions".* FROM "questions" WHERE "questions"."survey_id" = ? [["survey_id", 5]]
Rendered surveys/_form.html.erb (4.2ms)
Rendered surveys/edit.html.erb within layouts/application (7.3ms)
Completed 200 OK in 70ms (Views: 67.9ms | ActiveRecord: 0.5ms)
So my code ...
surveys_controller.rb
class SurveysController < ApplicationController
def index
#surveys = Survey.all
end
def show
#survey = Survey.find(params[:id])
end
def new
#survey = Survey.new
3.times do
question = #survey.questions.build
4.times { question.answers.build }
end
end
def create
#survey = Survey.new(survey_params)
if #survey.save
flash[:notice] = "Successfully created survey."
redirect_to #survey
else
render :action => 'new'
end
end
def edit
#survey = Survey.find(params[:id])
end
def update
#survey = Survey.find(params[:id])
if #survey.update_attributes(params[:survey])
flash[:notice] = "Successfully updated survey."
redirect_to #survey
else
render :action => 'edit'
end
end
def destroy
#survey = Survey.find(params[:id])
#survey.destroy
flash[:notice] = "Successfully destroyed survey."
redirect_to surveys_url
end
private
def survey_params
params.required(:survey).permit(:id, :survey, :notice)
end
end
Edit action view
<% title = "Edit Survey" %>
<%= render 'form' %>
<p>
<%= link_to "Show", #survey %> |
<%= link_to "View All", surveys_path %>
</p>
_form.html.erb
<%= form_for(#survey) do |f| %>
<% if #survey.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#survey.errors.count, "error") %> prohibited this survey from being saved:</h2>
<ul>
<% #survey.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<% f.fields_for :questions do |builder| %>
<%= render "question_fields", :f => builder %>
<% end %>
<p><%= f.submit "Submit" %></p>
<% end %>
_question_fields.html.erb
<p>
<%= f.label :content, "Question" %><br />
<%= f.text_area :content, :rows => 3 %><br />
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove Question" %>
</p>
<% f.fields_for :answers do |builder| %>
<%= render 'answer_fields', :f => builder %>
<% end %>
_answer_fields.html.erb
<p>
<%= f.label :content, "Answer" %>
<%= f.text_field :content %>
<%= f.check_box :_destroy %>
<%= f.label :_destroy, "Remove" %>
</p>
In each of the 7 projects I ran off the web...
It was the nesting of the array's within the params.require() that was the problem.. It's one thing to tell someone it has to be nested - it's another to show them the syntax when they are new :)
Example:
// Note this is from memory, as I deleted this version of the github..so it's not exactly right or tested...
params.require(:survey).permit(:id,:questions => [:id, :survey_id, :question, :answers => [:id, :question_id, :answer]])
Here's the break down of that same example in depth:
params.require(:survey).permit(
:id,
:questions => [:id, // This is the 1st nesting
:survey_id, :question, :answers => [:id, // This is 1st nested array ":questions"
:question_id, :answer] // End the 2nd nested array ":answers"
] // End the 2nd array ":questions"
) // End the ":surveys" array & the .permit as a whole
Im working on a simple app here that needs a settings page since I am new to rails I am a little lost here. I would like to get it setup in a database with one column as a key and one column as the value. I already have a few things setup here but I am having trouble getting my forms to update the settings working.
All I want to do is have a single settings page with multiple settings that can be changed in it. for now all settings are going to be text fields. With my current code im getting the error "undefined method `to_key' for #". so here is some code:
model: setting.rb
class Setting < ActiveRecord::Base
def self.method_missing(method_name, *args, &block)
if method_name[-1] == '='
handle_set_setting method_name.to_s.delete("="), args.first
else
handle_get_setting method_name
end
end
private
def self.handle_get_setting(name)
if setting = Setting.find_by(key: name.to_s)
setting.value unless setting.value.empty?
else
nil
end
end
def self.handle_set_setting(name, value)
if setting = Setting.find_or_create_by(key: name.to_s)
setting if setting.update(value: value.to_s)
end
end
end
Here is my settings_controller.rb (Im 100% sure I dont have much correct in here.)
class SettingsController < ApplicationController
before_action :set_settings, only: [:edit, :update, :show]
def index
#settings = Setting.all
end
def new
#settings = Setting.new
end
def update
#settings.update(params)
end
private
def params
params.require(:key).permit(:value, :etc)
end
def set_settings
#settings = Setting.find params[:key]
end
end
and here is my index.html.erb (pretty sure this is all wrong)
<h2> Settings </h2>
<h3> Movie Settings </h3>
<%= form_for(#settings) do |f| %>
<%= f.hidden :key => "cp_api" %>
<%= f.label :value %><br>
<%= f.text_field :value %>
<%= f.submit %>
<% end %>
Here is the error log:
Started GET "/settings" for ::1 at 2015-09-18 00:57:24 -0400
Processing by SettingsController#index as HTML
Setting Load (0.1ms) SELECT "settings".* FROM "settings"
Rendered settings/index.html.erb within layouts/application (3.6ms)
Completed 500 Internal Server Error in 7ms (ActiveRecord: 0.1ms)
ActionView::Template::Error (undefined method `to_key' for # <Setting::ActiveRecord_Relation:0x007fa186b88128>):
1: <h2> Settings </h2>
2:
3: <h3> Settings </h3>
4: <%= form_for(#settings) do |f| %>
5: <%= f.hidden :key => "cp_api" %>
6: <%= f.label :value %><br>
7: <%= f.text_field :value %>
app/views/settings/index.html.erb:4:in `_app_views_settings_index_html_erb__4580226212883122031_70165864193720'
Im sure its something really easy to figure out, but I'm just really lost here, Ive been bashing my head for 2 days on this problem and I just cant seem to figure it out.
Thanks!
You need to add #setting = Setting.New to your index method like below
def index
#settings = Setting.all
#setting = Setting.new
end
and change <%= form_for(#settings) do |f| %> to <%= form_for(#setting) do |f| %>
Also you need to change your params method to below
def params
params.require(:setting).permit(:value, :key)
end
And change <%= f.hidden :key => "cp_api" %> to <%= f.hidden_field :key => "cp_api" %> to avoid further issues
I'm trying to figure out why my form is submitting wrong. I'm trying to implement nested comments under posts and my form renders but submits to the wrong action. I've tried a few things but cannot get it to work. I can create a comment via the rails console but not through my form. I was going through a railscast where he uses a older version of rails. I figured the main difference would be strong parameters but it doesn't seem to be working and I can't figure out what I'm missing here. Thanks.
This is my log
Started GET "/posts/1?utf8=%E2%9C%93&authenticity_token=PJmmRV6hnY%2Bgm4cVe5LSdALHezbI3ehMkud0yYTaA%2FQ%3D&comment%5Bname%5D=Mark&comment%5Bemail%5D=hustada80%40gmail.com&comment%5Bcontent%5D=this+is+a+comment&commit=Create+Comment" for 127.0.0.1 at 2014-10-08 14:34:53 -0500
Processing by PostsController#show as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"PJmmRV6hnY+gm4cVe5LSdALHezbI3ehMkud0yYTaA/Q=", "comment"=>{"name"=>"Mark", "email"=>"hustada80#gmail.com", "content"=>"this is a comment"}, "commit"=>"Create Comment", "id"=>"1"}
Post Load (0.2ms) SELECT "posts".* FROM "posts" WHERE "posts"."id" = ? LIMIT 1 [["id", 1]]
Rendered comments/_form.html.erb (4.2ms)
Rendered comments/_comments.html.erb (0.1ms)
Rendered posts/show.html.erb within layouts/application (53.1ms)
Rendered layouts/_header.html.erb (0.5ms)
Rendered layouts/_footer.html.erb (0.1ms)
Completed 200 OK in 524ms (Views: 519.7ms | ActiveRecord: 0.2ms)
Here is my form ( a partial _form)
<div class="well">
<h4>Leave a comment</h4>
<form role="form" class="clearfix">
<%= form_for([#commentable, #comment]) do |f| %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :email %>
<%= f.text_field :email, class: 'form-control', required: true %>
</div>
<div class="form-group">
<%= f.label :content %>
<%= f.text_area :content, class: 'form-control', required: true %>
</div>
<%= f.submit class: 'btn btn-primary' %>
<% end %>
</div>
Posts controller
class PostsController < ApplicationController
def new
#post = Post.new
end
def show
#post = Post.find(params[:id])
#commentable = #post
#comments = #commentable.comments
#comment = Comment.new
end
def index
#post = Post.all
#posts = Post.order('created_at DESC')
###posts_by_month = Post.find(:all, :order => 'created_at DESC').group_by { |post| post.created_at.strftime("%B %Y") }
end
def month_count
#posts_by_month = Post.find(:all, :order => 'created_at DESC').group_by { |post| post.created_at.strftime("%B %Y") }
end
def create
#post = Post.new(post_params)
#post.save
redirect_to #post
end
private
def post_params
params.require(:post).permit(:title, :text)
end
Comments Controller
class CommentsController < ApplicationController
before_action :load_commentable
def index
#comments = #commentable.comments
end
def new
#comment = #commentable.comments.new
end
def create
#comment = #commentable.comments.new(comments_params)
if #comment.save
redirect_to #commentable, notice: "Comment created."
else
render :new
end
end
def destroy
end
private
# def load_commentable
# resource, id = request.path.split('/')[1, 2]
# #commentable = resource.singularize.classify.constantize.find(id)
# end
def load_commentable
klass = [Post].detect { |c| params["#{c.name.underscore}_id"]}
#commentable = klass.find(params["#{klass.name.underscore}_id"])
end
def comments_params
params.require(:comment).permit(:content, :email, :name)
end
end
routes
Rails.application.routes.draw do
root 'posts#index'
get "sign_up" => "users#new", :as => "sign_up"
get "/log-in" => "sessions#new"
post "/log-in" => "sessions#create"
get "/log-out" => "sessions#destroy", as: :log_out
resources :posts do
resources :comments
end
resources :users
resources :sessions
Try something like
<%= form_for([#commentable, #comment], url: post_comments_path, method: :post) do |f| %>
I'm using rails 4.0.8. I added a comment section to a model called 'Things', but I keep getting the same error "param is missing or the value is empty: thing" when I press the submit comment button. It says the error is in the Things#Controller. What am I doing wrong?
UPDATE: I removed the url path from the form, but a new error returns "Couldn't find Thing without an ID". The error is in Comments#Controller.
VIEW FOR THING/SHOW
<div id= "thing">
<h1>
<%= #thing.name %>
</h1>
<br>
<div id= "commentsection">
Comments
<div id= "comments">
<br>
<% #thing.comments.each do |c| %>
<%= c.username %>
<br>
<%= c.text %>
<% end %>
<%= form_for #comment, :url => thing_path do |f| %>
<%= f.label :username %>
<%= f.text_field :username %>
<%= f.label :comment %>
<%= f.text_field :text %>
<%= f.submit "Enter", class: "btn btn-small btn-primary" %>
<% end %>
</div>
</div>
</div>
THINGS CONTROLLER
class ThingsController < ApplicationController
def show
#thing = Thing.find(params[:id])
#thing.comments.build
#comment = Comment.new
end
def index
end
def new
#thing = Thing.new
#things = Thing.all
end
def create
#thing = Thing.new(thing_params)
if #thing.save
redirect_to #thing
else
render 'new'
end
end
private
def thing_params
params.require(:thing).permit(:name, :avatar)
end
end
COMMENTS CONTROLLER (I put asterisks around the line where the error is)
class CommentsController < ApplicationController
def show
#comment = Comment.find(params[:id])
end
def new
#comment = Comment.new
#comments = Comment.all
end
def create
****#thing = Thing.find(params[:thing_id])****
#comment = #thing.comments.create(comment_params)
redirect_to thing_path(#thing)
end
end
private
def comment_params
params.require(:comment).permit(:user, :text, :upvotes, :downvotes, :thing_id)
end
end
ROUTES
Website::Application.routes.draw do
get "comments/new"
get "comments/show"
get "things/new"
root 'home_page#home'
get "all/things/new" => 'things#new'
get "all/allthings"
resources :things
resources :good_comments
get "things/show"
get "things/results"
end
You are posting the #comment form to post '/things' path.
<%= form_for #comment, :url => thing_path do |f| %>
It should just be <%= form_for #comment do %> (Rails is smart enough to plug in the comments_path) or if you feel like being more explicit (even though it's not necessary)
<%= form_for #comment, url: :comments_path do %>
Another note though, if you want that Comment to be tied to that specific Thing then in your models it should be
Class Thing
has_many :comments
end
Class Comment
belongs_to :thing
end
Then make sure in your database comment has a thing_id foreign_key field and then your form for comment should actually look like
<%= form_for #thing, #comment do %>
<% end %>
I am new to Rails and working on creating a generic "facebook" type of app as practice with users and posts associated with each user. However, I'm currently having an issue where I think the form that I am using to create the posts is also being rendered out as a blank post with no post ID where I display all of the posts in a section below. I think that this post is being shown even before it is being saved to the database.
Here is my code in my view:
<div class="newpostcontainer">
<div class="newposttext">
<%= form_for([#user, #user.posts.build]) do |f| %>
<%= f.text_area :post, size: "69x1" %>
</div>
<div class="newpostsubmitbutton">
<%= f.submit %>
</div>
<% end %>
</div>
<% #user.posts.reverse_each do |p| %>
<div class="postedcontainer">
<div class="minipostpic">
<%= image_tag #user.photo.url, width: 32, height: 32 %>
</div>
<div class="nameofposter"><%= #user.name %></div>
<div class="dateofpost"><%= p.created_at%></div>
<div class="postcontent"><%= p.id%></div> <br>
<div class="postcontent"><%= p.post%></div> <br>
<div class="likecommentdelete">
<%= link_to "Delete", [p.user, p], method: :delete %> | Like | Comment
</div>
</div>
<%end%>
</div>
Here is my controller:
def index
#user = User.find(params[:user_id])
#posts = #user.posts.all
end
def create
#user = User.find(params[:user_id])
#post = #user.posts.create!(post_params)
redirect_to user_path(#user)
end
def show
#user = User.find(params[:user_id])
#post = #user.posts.find(params[:id])
redirect_to user_path(#user)
end
def destroy
#user = User.find(params[:user_id])
#post = #user.posts.find(params[:id])
#post.destroy
if #post.destroy
redirect_to user_path(#user)
else
redirect_to users_path
end
end
private
def post_params
params.require(:post).permit!
end
end
And here is my model:
class Post < ActiveRecord::Base
belongs_to :user
has_many :comments
validates_presence_of :post
end
I'm pretty sure the issue has something to do with my form to create the new post because when I remove it or comment it out, the extra blank post with no post ID goes away.
Any thoughts or suggestions?
Thank you!!
I think you need to permit the field values to be posted:
i.e.,
params.require(:post).permit!
should be
params.require(:post).permit(:name, :post)
then only it will POST I think.
Hope it helps :)
This is because of rails 4 strong parameter feature. You need to whitelist your active models parameters. For more details refer to here.
In your case you need to do something like this:
params.require(:post).permit(:post)
where the ":post" inside require is your model and the other one is your permitted field that is your textarea.
Several issues -
Form
<%= form_for([#user, #user.posts.build]) do |f| %>
Why are you building an associative object? #user.posts.build will not persist your data, and will cause all sorts of non-conventional issues I would highly recommending building the posts associative object in your controller's new action before using in the view, so you can do this:
#app/controllers/users_controller.rb
def new
#user = current_user
#user.posts.build
end
<%= form_for #user do |f| %>
Association
You're trying to edit the post attribute with this statement:
<%= f.text_area :post, size: "69x1" %>
This won't work in any circumstance, as :post is an association, not an object. Rails only allows you to change / add attributes to specific objects, which means you'll be better doing something like this:
<%= f.fields_for :posts do |p| %>
<%= p.text_area :title %>
<%= p.text_area :body %>
<% end %>
Strong Params
You're currently permitting all your params? You'll be better doing this:
def post_params
params.require(:user).permit(posts_attributes: [:title, :body])
end
Use Posts Controller
A better way will be to just use the posts_controller, like this:
#app/controllers/posts_controller.rb
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
#post.save
end
#app/views/posts/new.html.erb
<%= form_for #post do |f| %>
<%= f.text_field :title %>
<%= f.text_field :body %>
<% end %>