Form not displaying error messages for nested resource - ruby-on-rails

I am having trouble getting error messages to display when a user tries to submit a blank comment. Upon create failure it render 'posts/show' properly but it doesnt appear to be sending the #comment object that my error_messages partial expects. Any thoughts?
comments_controller.rb:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(comment_params)
#comment.user = current_user
if #comment.save
flash[:success] = "Comment created!"
redirect_to post_path(#post)
else
#comments = #post.comments.paginate(page: params[:page], :per_page => 5)
render 'posts/show' # => Renders but does not display errors???
end
end
posts_controller.rb:
def show
#post = Post.find(params[:id])
#comments = #post.comments.paginate(page: params[:page], :per_page => 5)
#comment = #post.comments.build if signed_in?
end
_comment_form.html.erb
<%= form_for([#post, #post.comments.build], :html => { :role => "form" }) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="form-group">
<%= f.label :content %>
<%= f.text_area :content, class: "form-control", placeholder: "Enter new comment..." %>
</div>
<div class="btn-group">
<%= f.submit "Post", class: "btn btn-large btn-primary" %>
</div>
<% end %>

<%= form_for([#post, #post.comments.build], :html => { :role => "form" }) do |f| %>
This always creates a form for blank comment object. So After create action, it does the same and that's why you are not getting any errors.
As you already done the initialization for the #comment in your create action, so you can use that in the form to get the error message for that #comment object. And I believe you have initialized the #comment object in your show action as well to work the partial form for both the show and create action.
So try using the following
<%= form_for([#post, #comment], :html => { :role => "form" }) do |f| %>

Related

Rails form runs POST when I need PATCH

I have a rails form that I want to use to edit an answer by running the update action (PATCH), but I keep getting this error:
No route matches [POST] "/answers/724"
This is the form:
<%= form_for :answers, url: { action: :update } do |f| %>
<%= f.label(#answer.question.question_text) %>
<%= f.text_area(#answer.answer_text) %>
<div class="form-group">
<%= f.submit "Submit", class: "btn btn-success" %>
</div>
<% end %>
Controller:
def edit
#answer = Answer.find_by(id: params[:id])
end
def update
#answer = Answer.find_by(id: params[:id])
if #answer.update(answer_text: params[:answer][:answer_text])
redirect_to '/answers/edit'
flash[:success] = "Answer Updated"
else
render 'edit'
end
end
How can I get this form to perform a PATCH request and not POST?
you need to explicitly pass the method to form_for
form_for :answers, url: { action: :update }, html: { method: :patch } do |f|

Trying to to add a nested post with the ancestry gem

I have topics and posts and they both have relationships. I've been following the guide on how to add a nested post but when i try to reply to a post i get Couldn't find Topic with 'id'=.
In my Posts controller
def create
#topic = Topic.find params[:topic_id]
#post = Post.new(post_params)
#post.user_id = current_user.id
#post.topic_id = #topic.id
if #post.save
redirect_to #topic
else
render :new
end
end
In my Topics controller
def show
#topic = Topic.find params[:id]
#post = Post.new(:parent_id => params[:parent_id])
#posts = #topic.posts
#topic.punch(request)
end
I'll keep it short for how i have my reply button in my topics/show.html.erb page
<% #posts.each do |post| %>
<%= link_to "Reply", new_topic_post_path(#topic, :parent_id => post) %>
<% end %>
Now this is my form
<%= simple_form_for [#topic, #post] do |f| %>
<%= f.hidden_field :parent_id %>
<%= f.input :content, as: :pagedown, input_html: { preview: true, rows: 10 }, label: 'Markdown' %>
<%= f.submit "Post", class: 'button expanded' %>
<% end %>
#Kristján Answered my question. I was missing params[:topic_id]

Mistake with my routes for uploading an image

I'm trying to solve a really simple problem with my code. I want to upload image into a post, I use paperclip, and the last step is not working.
That is my controller :
class PostsController < ApplicationController
def index
#posts = Post.all
end
def new
#post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
flash[:success] = "uccess!"
redirect_to post_path(#post)
else
flash[:error] = #post.errors.full_messages
redirect_to new_post_path
end
end
def show
#post = Post.find(params[:id])
end
private
def post_params
params.require(:post).permit(:title, :image, :prix, :adress, :description)
end
end
that my form :
<%= simple_form_for #post, url: root_path do |f|%>
<%= f.input :title, label: "Nom du plat" %>
<br>
<%= f.input :image, as: :file %>
<br>
<%= f.input :prix %>
<%= f.input :adress, label: "Localisation" %>
<%= f.input :description %>
<br>
<%= f.button :submit %>
<% end %>
and that my view :
<%= image_tag (#post.image.url(:medium)) %>
<br>
<%= #post.description %>
<br>
<button>
<%= link_to "Home", root_path %>
</button>
So if you go through, and you spot a stupid mistake, please let me know.
You're calling root_path as the helper in your form when you need to call the route for post. Run rake routes and look for the create action related to post, which should be the same as the get route for the show action.
This should not be root_path:
<%= simple_form_for #post, url: root_path do |f|%>

comments validation errors not shown in posts view

I am working on basic blog engine and i have applied validations on comments but when i do a submit it doesn't show errors, instead it shows ActiveRecord::RecordInvalid by rails which is default.
my comments controller is
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create!(params[:comment])
redirect_to #post
end
my posts/show view is as below which is working fine for commenting
<%= form_for [#post, Comment.new] do |f| %>
<p class="comment-notes">Your email address will not be published. Required fields are marked <span class="required">*</span></p>
<p>
<b><%= f.label :name, "Name * " %></b><%= f.text_field :name %><br /></p>
<p>
<b><%= f.label :body, "Comment" %></b><%= f.text_area :comment, :cols => 60, :rows => 5 %>
</p>
<p>
<%= f.submit "Post Comment" %>
</p>
can anybody help me to show validation errors on the same posts/show view?
thanks in advance
replace
#comment = #post.comments.create!(params[:comment])
redirect_to #post
with
#comment = #post.comments.create(params[:comment])
if #comment.errors.any?
render "posts/show"
else
redirect_to #post
end
unlike create, create! will raise error if validations fail
in posts/show
<%= form_for [#post, Comment.new] do |f| %>
<% if #comment && #comment.errors.any? %>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
<% end %>
...
Try this:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.new(params[:comment])
if #post.save
redirect_to #post
else
flash[:error] = "Correct errors"
end
end
In Post model:
accepts_nested_attributes_for :comments
or
If you don't want to make as nested model:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.new(params[:comment])
if #comment.save
redirect_to #post
else
flash[:error] = "Correct errors"
end
end

Validate form called through another controller

Im writing a blog engine, So I have a post view (show.html.erb) that shows a post, comments list and a comments form.
I call the form this way:
<%= render :partial => 'comments/form', :locals => {:comment => #post.comments.new} %>
Im not sure if passing the comment that way is correct, but at least I get the post_id on the new comment.
This is my form (_form.html.erb on comments view):
<%= form_for comment, :action => "create" do |f| %>
<% if comment.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(comment.errors.count, "error") %> prohibited this comment from being added:</h2>
<ul>
<% comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.hidden_field :post_id %>
<p>
<%= f.label :name %>
<%= f.text_field :name %>
</p>
<p>
<%= f.label :email %>
<%= f.text_field :email %>
</p>
<p>
<%= f.label :url %>
<%= f.text_field :url %>
</p>
<p>
<%= f.label :content %>
<%= f.text_area :content %>
</p>
<p class="no-border">
<%= f.submit "Post", :class => "button" %>
</p>
<% end %>
And this the action:
def create
#comment = Comment.new(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to :back }
else
format.html { redirect_to :back }
end
end
end
A bit verbose but I want to add more stuff.
I can add comments perfectly but I can't view validation errors.
I leave all blank (my model have validation stuff) and I see that the comment created in the create action have the errors and go to the else path.
But... The form doesn't show any errors.
I think that I have an object with the erorrs but when I redirect back, the object I pass to the form is a new one again and doesn't have the errors.
So, where is the problem?
EDIT: Extra stuff:
Im my show.html.erb I also have this (before the form):
<ol class="commentlist">
<%= render #post.comments %>
</ol>
So, When in the show action I put the extra variable:
def show
#post = Post.find(params[:id])
#comment = #post.comments.new
It seems that the render wants to render the empty comment too and make an exception.
How to bypass that?
When you redirect back, you are calling the PostsController#show action again which will reset all of the instance variables. If you wanted to save state after the failed CommentsController#create call, you would need to call render 'posts/show' instead of redirect :back which would reuse the instance variables which were declared in the current action
def create
# assuming you have nested the comments routes underneath posts...
#post = Post.find(params[:post_id])
#comment = #post.comments.build(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to :back }
else
format.html do
# remember to declare any instance variables that PostsController#show requires
# e.g. #post = ...
render 'posts/show'
end
end
end
end
You would also need to make sure that the partial uses #comment instead of creating a new comment each time
<%= render :partial => 'comments/form', :locals => {:comment => #comment } %>
And make sure the PostsController declares #comment
# e.g. inside PostsController
def show
#post = Post.find(params[:id])
#comment = Comment.new
end
The most important thing to remember is to make sure that the code inside the failed create call initializes all the instance variables that the PostsController#show action template requires otherwise you'll get errors.

Resources