0

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.

4 Answers 4

2

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.

Sign up to request clarification or add additional context in comments.

Comments

2

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.

2 Comments

Actually, you're talking about instance variables. Global variables start with $ sign. Look here for details on this topic: stackoverflow.com/questions/11495098/…
Thanks Alexey Shein. That's exactly that I want to say.
1

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 

Comments

1

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 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.