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
Related
I want to create a new article object, but have this error:
Showing
/Users/levanngoc/code/blog_app/app/views/articles/new.html.erb where
line #3 raised:
undefined method `errors' for nil:NilClass
How can I fix it?
this is my controller:
class ArticlesController < ApplicationController
def index
#article = Article.all
end
def show
#article = Article.find(params[:id])
end
def new
end
def edit
end
def create
#article = Article.new(article_params)
if #article.save
redirect_to #article
else
render 'new'
end
end
def update
end
def destroy
end
private
def article_params
params.require(:article).permit(:title, :text)
end
end
this is my view file: new.html.erb
<h1>New Article</h1>
<%= form_with scope: :article,url: articles_path , local: true do |form| %>
<% 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>
<%= form.label :title %><br>
<%= form.text_field :title %>
</p>
<p>
<%= form.label :text %><br>
<%= form.text_area :text %>
</p>
<p>
<%= form.submit %>
</p>
<% end %>
<%= link_to 'Back', articles_path %>
Your new view uses #article but the new action in the controller doesn't create this instance variable. You must change it to:
def new
#article = Article.new
end
You must declare:
#article = Article.new
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.
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.
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
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.