How to populate form in nested model when error occurs? - ruby-on-rails

Running Rails 3.2.1.
I went through the "Getting started" guide on the Ruby on Rails site. I have set up a blog post where someone can comment on the posts.
I modified the example to show an error when I enter in comments that don't validate (no name or comment text).
(A post has multiple comments, etc.)
However, how do I have Rails put this problematic comment back in the form, instead of the page?
Here is my create method in the comments controller:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(params[:comment])
respond_to do |format|
if #comment.save
format.html { redirect_to(#post, :notice => 'Comment was successfully created.') }
else
format.html { render 'posts/show' }
end
end
end
Here is my show.html.erb from posts:
<%= render #post %>
<h3>Comments</h3>
<%= render #post.comments %>
<h3>Add a comment</h3>
<%= render "comments/form" %>
<p>
<% if user_signed_in? %>
<%= link_to 'Edit', edit_post_path(#post) %> |
<% end %>
<%= link_to 'Back', posts_path %>
</p>
And here is my comment form partial:
<%= form_for([#post, #post.comments.build]) do |f| %>
<%= render "shared/error_messages", :target => #comment %>
<div class="field">
<%= f.label "Name" %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :body %><br />
<%= f.text_area :body %>
</div>
<div class="actions">
<%= f.submit "Add Comment!" %>
</div>
<% end %>
And here's my comment partial:
<p>
<strong><%= comment.name %></strong><br />
<%= comment.created_at.try(:strftime, "on %A, %B %d %Y at %H:%M:%S") %><br />
<%= simple_format(h(comment.body), :sanitize => true) %>
</p>

In your form when you return from an error.
<% if #comment.errors.any? %>
<div id="errorExplanation">
<h2><%= pluralize(#comment.errors.count, "error") %> prohibited this post from being saved:</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

Related

Showing error messages for nested resources in Rails

I am creating my first app, simple blog, and I don't know how to show error messages for nested resource(comments) that doesn't pass validation.
this is create action for comments:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.create(comment_params)
redirect_to post_path(#post)
end
this is comment form:
<%= form_for([#post, #post.comments.build]) do |f| %>
<p>
<%= f.label :commenter %><br />
<%= f.text_field :commenter %>
</p>
<p>
<%= f.label :text %><br />
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
I tried with:
def create
#post = Post.find(params[:post_id])
#comment = #post.comments.build(comment_params)
if #comment.save
redirect_to post_path(#post)
else
render '/comments/_form'
end
end
and:
<% if #comment.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#comment.errors.count, "error") %> prohibited
this comment from being saved:
</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
But I don't know whats wrong.
You can't render a partial from a controller. A better alternative is just to create a new view.
class CommentsController
def create
if #comment.save
redirect_to post_path(#post), success: 'comment created'
else
render :new
end
end
end
app/views/comments/new.html.erb:
<% if #comment.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#comment.errors.count, "error") %> prohibited
this comment from being saved:
</h2>
<ul>
<% #comment.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= render partial: 'form', comment: #comment %>
app/views/comments/_form.html.erb:
<%= form_for([#post, local_assigns[:comment] || #post.comments.build]) do |f| %>
<p>
<%= f.label :commenter %><br />
<%= f.text_field :commenter %>
</p>
<p>
<%= f.label :text %><br />
<%= f.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>

Flash alert Error not displaying Rails

So I have two flash notice that should appear one if a post is saved successfully and another if there is an error creating a new post . I implemented it a while back but I just realized that the error flash isn't being displayed properly. All it displays is a red empty notice on top of the window, while the notice for a "successful save" does appear correctly.
for my controller i have :
def create
#topic = Topic.new
#topic.name = params[:topic][:name]
#topic.description = params[:topic][:description]
#topic.public = params[:topic][:public]
if #topic.save
redirect_to #topic, notice: "Topic was saved successfully."
else
flash.now[:alert] = "Error creating topic. Please try again."
render :new
end
end
new post view :
<div class="col-md-8">
<%= render partial: 'form', locals: { topic: #topic, post: #post } %>
</div>
</div>
_form.html:
<%= form_for [topic, post] do |f| %>
<% if post.errors.any? %>
<div class="alert alert-denger">
<h4><%= pluralize(post.errors.count, "error") %>.</h4>
<ul>
<% post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<%= form_group_tag(post.errors[:title]) do %>
<%= f.label :title %>
<%= f.text_field :title, class: 'form-control', placeholder: "Enter post title" %>
<% end %>
<%= form_group_tag(post.errors[:body]) do %>
<%= f.label :body %>
<%= f.text_area :body, rows: 8, class: 'form-control', placeholder: "Enter post body" %>
<% end %>
<div class="form-group">
<%= f.submit "Save", class: 'btn btn-success' %>
</div>
<% end %>
Please put this in application.html.erb file.
<% flash.each do |key, value| %>
<div class="flash <%= key %>"><%= value %></div>
<% end %>
Try to add flash massages in your application.html.erb:
<% flash.each do |key, value| %>
<div class="alert alert-<%= key %>">
<%= value %>
</div>
<% end %>
usually it put above <%= yield %>

Rails Getting Started Tutorial partial not woking for new blog post

I'm working my way through the rails "Getting Started" tutorial, and I'm stuck at the point where they introduce partials. For some reason the partial doesn't work as described when rendered from new.html.erb, although it does work when rendered from edit.html.erb. When clicking "New" to get to the new.html.erb, I'm getting the following error:
Error:
"First argument in form cannot contain nil or be empty"
for the first line in the following partial:
_form.html.erb:
<%= form_for #post do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited
this article from being saved:</h2>
<ul>
<% #post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :title %><br/>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :text %><br/>
<%= f.textarea :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
new.html.erb:
<h1>New Post</h1>
<%= render 'form' %>
<%= link_to 'Back', posts_path %>
edit.html.erb:
<h1>Edit post</h1>
<%= render 'form' %>
<%= link_to 'Back', posts_path %>
posts_controller.rb:
...
def new
end
...
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update(post_params)
redirect_to #post
else
render 'edit'
end
end
...
It looks as though the new.html.erb doesn't know about the #post variable if it's a new post. The original new.html.erb looked like this:
<h1>New Post</h1>
<%= form_for :post, url: posts_path do |f| %>
...
... other than the use of symbols instead of #post, it's identical to the partial form.
Any ideas?
You don't set #post instance variable in your Posts#new action (and that's why it's nil). You should have:
def new
#post = Post.new
end
in your PostsController.

Errors for nested resource not displaying even if I'm using "target"?

I have the following:
routes.rb:
resources :posts do
resources :replies
end
replies_controller.rb:
class RepliesController < ApplicationController
def create
#post = Post.find(params[:post_id])
#reply = #post.replies.build(params[:reply])
#reply.user_id = current_user.id
if #reply.save
flash[:success] = "reply created!"
redirect_to post_path(#post)
else
redirect_to post_path(#post)
end
end
replies/_form.html.erb:
<%= form_for([#post, #post.replies.build]) do |f| %>
<%= render 'shared/error_messages', object: f.object, target: #reply %>
<div class="field">
<%= f.text_area :content, placeholder: "Enter reply content" %>
</div>
<%= f.submit "Reply", class: "btn btn-large btn-primary" %>
<% end %>
posts/show.html.erb:
<div class="span8">
<%= render 'replies/form' %>
</div>
shared/error_messages.html.erb:
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
I'm not sure why the errors messages for the replies are not displaying since I'm using target: #reply (:content and :user_id are required).
Any suggestions to fix this?
In create method's else section you have to render the post_path(#post) not redirect the post_path(#post)
try this in else part of create section
render :template => 'posts/show'
So that your current #reply object will persist for your error messages.
redirect_to post_path(#post) will redefine #reply object in show action (I assume you have defined #reply object there).
In posts/show action, build your reply object there and assign it to #reply instance object.
#reply = #post.replies.build
Now in replies/_form.html.erb:
change #post.replies.build to #reply
i.e
<%= form_for([#post, #post.replies.build]) do |f| %>
to
<%= form_for([#post, #reply]) do |f| %>
Also assign #reply to object variable while rendering 'shared/error_messages' partial,
<%= form_for([#post, #reply]) do |f| %>
<%= render :partial => 'shared/error_messages', :locals => {:object => #reply} %>
<div class="field">
<%= f.text_area :content, placeholder: "Enter reply content" %>
</div>
<%= f.submit "Reply", class: "btn btn-large btn-primary" %>
<% end %>
Also make partial for error_messages in shared folder (shared/_error_messages). In this partial paste your code which is in shared/error_messages
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-error">
The form contains <%= pluralize(object.errors.count, "error") %>.
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li>* <%= msg %></li>
<% end %>
</ul>
</div>

Rails 3.1 - Extra result of each loop?

This is really simple, but i'm going slightly mad and probably missing something that's staring me in the face. Can anyone help?
Basically, I have a simple each loop that's returning an extra rogue line. Even when there's nothing in the db, I get one line returned!
My show view including the loop is:
<p id="notice"><%= notice %></p>
<p>
<b>Header:</b>
<%= #mailer.header %>
</p>
<p>
<b>Subtext:</b>
<%= #mailer.subtext %>
</p>
<div id="" class="" padding-left: 30px;>
<h3>Mailer Products </h3>
<ol id="mailer-Product-list">
<% #mailer.mailer_products.sort_by { |mailer_products| mailer_products.position }.each do |mailer_product| %>
<%= content_tag_for :li, mailer_product do %>
<%= mailer_product.product.cat_no %>
<% end %>
<% end %>
</ol>
<%#= link_to 'Done', #product, :class => "standard-button" %>
</div>
<%= form_for([#mailer,#mailer.mailer_products.build]) do |f| %>
<div class="field">
<%= f.label :product_id %><br />
<%= f.text_field :product_id %>
</div>
<div class="field">
<%= f.hidden_field :mailer_id, :value => #mailer.id %>
</div>
<div class="actions">
<%= f.submit "Add Product" %>
</div>
<% end %>
<%= link_to 'Edit', edit_mailer_path(#mailer) %> |
<%= link_to 'Back', mailers_path %>
The controller code is:
class MailersController < ApplicationController
def show
#mailer = Mailer.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.json { render :json => #mailer }
end
end
class MailerProductsController < ApplicationController
def index
#mailer_products = MailerProduct.find(:all)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #mailer_products }
end
end
end
end
Your call to form_for looks like this
form_for([#mailer,#mailer.mailer_products.build]) do |f|
You get an extra blank item because that's what calling .build on mailer_products does: it appends a new instance to the array
When the form is after the loop this doesn't matter, but when things are the other way around the loop will be on the modified array
My usual mistake is adding a <%= instead of a <% on the loop...
<%= #foo.each do |itme| %>
# do stuff
<% end %>
which should be
<% #foo.each do |itme| %>
# do stuff
<% end %>
Double check your tags...

Resources