I am trying to create a Rails blog app with this tutorial
I am stuck on the step that validates that the fields a user enters are not empty. However, if I try to pass empty fields, I get this error:
NoMethodError in Posts#create
Showing C:/Users/irowe/Documents/GitHub/Rails-Blog/blog/app/views/posts/new.html.erb where line #3 raised:
undefined method `errors' for nil:NilClass
Here is my post controller:
class PostsController < ApplicationController
def index
@posts = Post.all.order(created_at: :desc)
end
def show
end
def new
@post = Post.new
end
def create
p = Post.new(title: params[:post][:title], content: params[:post][:content])
if p.save
flash[:notice] = 'Successfully created a new post!'
redirect_to root_path
else
flash[:alert] = 'Something went awry...'
render :new
end
end
end
and my "new post" view
<h1>New Post</h1>
<ul>
<% @post.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
<%= form_for @post, url: create_post_path do |f| %>
<%= f.text_field :title %>
<br />
<%= f.text_area :content %>
<br />
<%= f.submit %>
<% end %>
And the post model
class Post < ActiveRecord::Base
validates_presence_of :title
validates_presence_of :content
before_validation :preval
private
def preval
if self.title
self.title = self.title.strip
end
if self.content
self.content = self.content.strip
end
end
end
I have seen other answers like this but they just recommend to make sure post
is not nil
, which I have made sure it isn't. Any ideas on how to make sure the validation woks? I am totally new to Rails.
You have to change your variable local into instances variable. To make instances variable, you can only add @
. It means the variable can be used in your new.html.erb file. For example:
def create
@post = Post.new(title: params[:post][:title], content: params[:post][:content])
if @post.save
flash[:notice] = 'Successfully created a new post!'
redirect_to root_path
else
flash[:alert] = 'Something went awry...'
render :new
end
end
This is good tutorial from rails guide rails guide to get started . I hope this tutorial can help you a lot.
NilClass
The error you're getting is standard if Rails is trying to manipulate an object which doesn't exist...
for nil:NilClass
For Ruby, there is no such thing as Nil
- it translates it into a NilClass
object. Thus, if you're trying to call the errors
method on this object, it will raise an exception.
The error is with this line:
<% @post.errors.full_messages.each do |msg| %>
Now, this won't be the cause of the error, just the symptom. It means that @post
doesn't exist. To remedy this, you need to look at why:
def create
p = Post.new(title: params[:post][:title], content: params[:post][:content])
if p.save
flash[:notice] = 'Successfully created a new post!'
redirect_to root_path
else
flash[:alert] = 'Something went awry...'
render :new
end
end
With this, you need to do several things:
Instance Variable
You need to make an instance variable , which will then be available in the view:
def create
@post = Post.new post_params
if @post.save
This should allow your view to access the @post
variable (which it wouldn't do it it were just local in scope).
Conditional
Secondly, you may wish to make the errors
invocation conditional:
<% if @post.errors.any? %>
<% @post.errors.full_messages.each do |msg| %>
This should get it working for you.
The issue is in your create
action. In it, you are using the local variable p
to store the Post
. However, when the validations fail, your code renders the new
view. That view is looking for the instance variable @post
. So simply, change your code to this:
@post = Post.new(title: params[:post][:title], content: params[:post][:content])
if @post.save
I'm guessing you don't get the error when you open the new
form, but only when you submit the form and it has errors.
That would be because you render the new
form again here:
flash[:alert] = 'Something went awry...'
render :new
render
simply renders the form, it does not redirect to the new
action.
And you never set post
in your create
action.
An easy fix would be to change these two lines
p = Post.new(title: params[:post][:title], content: params[:post][:content])
if p.save
to this:
@post = Post.new(title: params[:post][:title], content: params[:post][:content])
if @post.save
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.