GMA
GMA

Reputation: 6096

Rspec: No route matches {:action=>"show", :controller=>"posts", :id=>nil}

I'm trying to create a very simple blog using Rails, for my own education. It's the first Rails app I've ever created other than from working through tutorials.

So far I just have a very simple model where each post has only a string for the title and a string for the content. Everything works fine and as expected in the browser, but I can't get the tests to pass.

Here's are the failing test in my Rspec code (spec/requests/post_spec.rb):

require 'spec_helper'

describe "Posts" do

  .
  .
  .

  describe "viewing a single post" do

    @post = Post.create(title: "The title", content: "The content")

    before { visit post_path(@post) }

    it { should have_selector('title',    text: @post.title) }
    it { should have_selector('h1',       text: @post.title) }
    it { should have_selector('div.post', text: @post.content) }

  end

end

This gives me the same error message for all 3:

Failure/Error: before { visit post_path(@post) }
     ActionController::RoutingError:
       No route matches {:action=>"show", :controller=>"posts", :id=>nil}

So it seems to me the problem is that the line @post = Post.create(...) is creating a post without an id, or else it's not saving the post to the test database correctly. How do I fix this? And am I going about this the right way in the first place, or is there a better way I could be creating the test post/testing the page?

This is only a problem in testing. When I view a single post in the browser everything looks fine. The Posts controller is: (I have edited this since posting the original question)

class PostsController < ApplicationController
  def new
    @post = Post.new
  end

  def create
    @post = Post.new(params[:post])
    if @post.save
      redirect_to posts_path, :notice => "Post successfully created!"
    end
  end

  def index
  end

  def show
    @post = Post.find(params[:id])
  end
end

And here's the Post model in its entirety:

class Post < ActiveRecord::Base
  attr_accessible :content, :title

  validates :content, presence: true
  validates :title,   presence: true
end

config/routes:

Blog::Application.routes.draw do
    resources :posts

    root to: 'posts#index'
end

app/views/posts/show.html.erb:

<% provide(:title, @post.title) %>

<h1><%= @post.title %></h1>

<div class="post"><%= @post.content %></div>

Upvotes: 1

Views: 5600

Answers (3)

tw airball
tw airball

Reputation: 1359

Your instance variable needs to go into the before block. (the test is trying to goto /posts/:id/show and params[:id] in this case is nil as @post hasnt been created)

try:

before do
    @post = Post.create(title: "The title", content: "The content") 
    visit post_path(@post)
end

Upvotes: 2

Chris Lewis
Chris Lewis

Reputation: 1325

Do you need to put your 'before' stuff outside the test? This works for me:

require 'spec_helper'
describe "Posts" do

  before(:each) do 
    @post = Post.create(title: "The title", content: "The content")    
  end

  describe "viewing a single post" do
    it "should show the post details" do
      get post_path(@post) 
      response.status.should be(200)
      # do other tests here .. 
    end
  end
end

Upvotes: 1

Richlewis
Richlewis

Reputation: 15374

Ok so it seems your new and create actions are empty?? Try

def new
@post =Post.new
end

def create
@post = Post.new(params[:post])
if @post.save
  redirect_to posts_path, :notice => " Post successfully created."
end
end

and then your view for new needs to have a form_for @post

You cant create a new post without this and only when this is successful your posts will e assigned ids

Upvotes: 1

Related Questions