Rails: Error Messages Partial Not Rendering - ruby-on-rails

I can see in my console that the erorr_messages partial I made is getting rendered, and if a comment does not pass validations, then it will not be posted, but I can't get the actual error contents to render.
Error Partial:
<% if object.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger">
The form contains <%= pluralize(object.errors.count, "error") %>
</div>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
Comment form
<%= form_for #comment, url: comments_path do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.hidden_field :user_id, value: current_user.id %>
<%= f.hidden_field :post_id, value: post.id %>
<%= f.text_area :content, size: "60x2", placeholder: "Comment on this post..." %>
<%= f.submit "Comment" %>
Post Form
<%= form_for [#user, #post] do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<%= f.text_area :content, size: "60x12", placeholder: "What do you want to say?" %>
<%= f.submit "Post" %>
Users/show
<% if #user == current_user %>
<h4>Welcome <%= current_user.email %>! </h4>
<%= render "notifications" %>
<%= render 'shared/post_form' %>
<%= render 'feed' %>
<% end %>
class CommentsController < ApplicationController
def index
#comments = Comment.all
end
def new
#comment = Comment.new
#user = User.find(params[:user_id])
end
def create
#user = current_user
#comment = #user.comments.build(comment_params)
if #comment.save
flash[:success] = "Comment Posted!"
redirect_back(fallback_location: root_path)
else
flash[:danger] = "Could not post comment"
redirect_back(fallback_location: root_path)
end
end
private
def comment_params
params.require(:comment).permit(:content, :user_id, :post_id)
end
end
class PostsController < ApplicationController
def index
#posts = Post.all
#user = User.find(params[:user_id])
#comment = Comment.new
end
def new
#post = Post.new
#user = User.find(params[:user_id])
end
def create
#post = current_user.posts.build(post_params)
if #post.save
flash[:success] = "Posted!"
redirect_to user_path(current_user)
else
flash[:danger] = "Post could not be submitted"
redirect_to users_path
end
end
private
def post_params
params.require(:post).permit(:content)
end
end

In your CommentsController#create, when the save fails, rather than redirecting:
redirect_back(fallback_location: root_path)
Try staying on the same page and just rendering the "new" template:
render action: "new"
If you redirect, the browser will make a second request and #comment will get overwritten with a freshly-built Comment.
If you stay on the same page and render the "new" template, it will use the #comment instance that's already loaded and which failed to save (this instance has all the validation errors set on it).
P.S. the flash message works because that's what flash is for - a way to store messages in your session so that they survive across redirects.

Related

It seems my 'new.html.erb' file does not rerender

I'm trying to display errors conditionally.
Here are my two files
new.html.erb
<h1>Create a New Article</h1>
<% if #article.errors.any? %>
<h2>Please fix the following errors</h2>
<ul>
<% #article.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<% end %>
<%= form_with scope: :article, url: articles_path, local: true do |f| %>
<p>
<%= f.label :title %> <br/>
<%= f.text_field :title %>
</p>
<p>
<%= f.label :description %> <br/>
<%= f.text_area :description %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
and articles_controller.rb
class ArticlesController < ApplicationController
def show
#article = Article.find(params[:id])
end
def index
#articles = Article.all
end
def new
#article = Article.new
end
def create
#article = Article.new(params.require(:article).permit(:title, :description))
if #article.save
redirect_to #article
else
puts #article.errors.any?
render 'new'
end
end
end
In my def create action I want to rerender my new.html.erb which should display errors. For some reason I don't think it rerenders.
Thanks for your help
So I figured it out with help from some people on Udemy. In Rails 7 we have to add status: :unprocessable_entity after the render new like so
def create
#article = Article.new(params.require(:article).permit(:title, :description))
if #article.save
redirect_to #article
else
puts #article.errors.any?
render 'new', status: :unprocessable_entity
end
end

First argument in form cannot contain nil or be empty (rails 5)

I've been following the rails blog tutorial (you know, that one ) and i've come to a point where every time i reference #articles on the update form, rails takes it as a nil, it says:
First argument in form cannot contain nil or be empty
Here's the form
<h1>Edit article</h1>
<%= form_for #article do |f| %>
<% if #article.errors.any? %>
<div id="error_explanation">
<h2>
<%= pluralize(#article.errors.count, "error") %> prohibited
this article from being saved:
</h2>
<ul>
<% #article.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.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
<%= link_to 'Back', articles_path %>
And the controller for the articles:
class ArticlesController < ApplicationController
def new
#article = Article.new
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def show
#article = Article.find(params[:id])
end
def index
#articles = Article.all
end
def update
#article = Article.find(params[:id])
if #article.update(article_params)
redirect_to #article
else
render 'edit'
end
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
It does not look like you have an edit method in your Articles controller.
def edit
#article = Article.find(params[:id])
end
Just so it is clear. The edit method is what is called with the GET route that shows the form. Update is the PATCH/PUT route that takes the form in and updates the record. So, the form is shown by the edit method via GET, and processed by the update method via PUT/PATCH.

ArgumentError in Posts#edit - first argument nil

I am going through the "Getting Started with Rails Tutorial" and am stuck on update aka Edit. It is throwing the ArgumentError in Posts#edit - first argument in form can't be nil or empty. Here is the highlighted line:
First argument in form cannot contain nil or be empty
Extracted source (around line #1):
<%= form_for #post do |f| %>
It seems to have started when I implemented the partial forms part of the tutorial.
Here is the post_contoller, edit action and _forms.html respectively:
Post_controller:
class PostsController < ApplicationController
def new
#post = Post.new
end
def create
#post = Post.new(params[:post].permit(:title, :text))
if #post.save
redirect_to #post
else
render 'new'
end
end
def show
#post = Post.find(params[:id])
end
def index
#posts = Post.all
end
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title, :text))
redirect_to #post
else
render 'edit'
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to posts_path
end
private
def post_params
params.require(:post).permit(:title, :text)
end
end
Edit.html
<h1>Edit post</h1>
<%= render 'form' %>
<%= link_to 'Back', posts_path %>
_form.html
<%= form_for #post do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited
this post 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.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
The error shows an ID of "7" which is the record I am trying to update.
All other functions work (show, new, delete) and BTW "new" uses the same partial form and works fine.
Any help would be much appreciated. Thanks!
U should add this in your _controller.rb
def edit
#post = Post.find(params[:id])
end
you have to pass in the post object as local. You cannot directly access instance variables defined in controller in partial. It will be nil
<h1>Edit post</h1>
<%= render :partial => 'form', :locals => {:post => #post} %>
<%= link_to 'Back', posts_path %>
In the partial
<%= form_for post do |f| %>
check below the private is used for the below function only and write all functions above this:
private
def article_params
params.require(:article).permit(:title, :text)
end

Getting undefined method `errors' for nil:NilClass

I'm doing the Ruby on Rails tutorial at http://guides.rubyonrails.org/getting_started.html
However when I get to "5.11 Adding Some Validation", after adding the error message to display when I try to create a new post from the index view I get
"undefined method `errors' for nil:NilClass"
This is the error line highlighted.
I have already created a new Post in my new action in the controller.
Here is the source
new.html.erb
<h1>New Post</h1>
<%= form_for :post, url: posts_path do |f| %>
<% if #post.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#post.errors.count, "error") %> prohibited this post 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.text_area :text %>
</p>
<p>
<%= f.submit %>
</p>
<% end %>
posts_controller.rb
class PostsController < ApplicationController
def new
#Post = Post.new
end
def create
#post = Post.new(post_params)
if #post.save
redirect_to #post
else
render 'new'
end
end
def show
#post= Post.find(params[:id])
end
def index
#posts = Post.all
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
private
def post_params
params.require(:post).permit(:title, :text)
end
end
Thanks.
Change
#Post = Post.new
To
#post = Post.new
Subtle but deadly
You've got error in your controller:
def new
#Post = Post.new
end
just change #Post to #post.

Embedding form partial in unconventional view

I have rendered the regular scaffold form partial for a task model in my user show view. My thinking been so the user can post and see the post on the same page. I defined a task in the user show action like so
def show
#user = User.find(params[:id])
#task = current_user.tasks.new
respond_to do |format|
format.html # show.html.erb
format.json { render json: #user }
end
end
And it does create the post but it does not show them. Any ideas as to why that is ?
Show page
#_form
<%= form_for(#task) do |f| %>
<% if #task.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#task.errors.count, "error") %> prohibited this task from being saved:</h2>
<ul>
<% #task.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :description %><br />
<%= f.text_field :description %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
#_form
#index page
<% current_user.tasks.each do |task| %>
<%= task.description %>
<% end %>
This is weird because you find a #user, but you use current_user to create a new task instance for your form:
#user = User.find(params[:id])
#task = current_user.tasks.new
I assume current_user already found the user model according to a cookie, session or token so you probably do not need #user in your show action.
With that aside, if you're concerned with the view not displaying the list of the current_user's tasks, then you'll need to make sure the view has the proper markup, hence you should show us what your view currently looks like as well. Here's what I'm assuming you're trying to do:
class UsersController < ApplicationController
def show
#task = current_user.tasks.new
respond_to do |format|
format.html
format.json { render json: current_user }
end
end
end
class TasksController < ApplicationController
def create
#task = current_user.tasks.new params[:task]
if #task.save
# Send a new request to users#show
redirect_to current_user
else
# No request will be sent to users#show and the template will just get
# rendered with #task containing the same values from the initial request
# with form input
render 'users/show'
end
end
end
# app/views/users/show.html.erb
<ul><%= render current_user.tasks %></ul>
<%= form_for #task do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
# app/views/tasks/_task.html.erb
<li><%= task.name %></li>

Resources