Search code examples
rubyrspeccapybarapadrino

undefined method for nil:NilClass in RSpec, even though manual test passes


I'm getting a very weird error, because it's all working perfectly in the browser i.e. the posts are displayed and the author's name is displayed. No errors.

However, the feature test is breaking, and I have no idea why. It's very strange.

posts_features_spec.rb:

require 'spec_helper'
require_relative '../support/spec_helper_methods'

feature "Post Features" do
  include SpecHelperMethods
  let(:user){ User.create(name: "Andy", email: "[email protected]", password: "password", password_confirmation: "password") }

  describe "Creating Posts" do
    it "Can create a post" do
      visit '/'
      click_on "Sign Up"
      fill_in 'user[name]', with: "Bob"
      fill_in 'user[email]', with: "[email protected]"
      fill_in 'user[password]', with: "password"
      fill_in 'user[password_confirmation]', with: "password"
      click_on 'Sign Up'
      click_on 'Login'
      fill_in 'email', with: "[email protected]"
      fill_in 'password', with: "password"
      click_on 'Login'
      expect(page).to have_content "Successfully signed in!"
      click_on "Create Post"
      fill_in 'post[title]', with: "Title99"
      fill_in 'post[body]', with: "Body99"
      click_on "Post"
      expect(current_path).to eq '/posts'
      expect(page).to have_content "Title99"
      expect(page).to have_content "Body99"
      expect(page).to have_content "Bob"
      expect(page).to have_content "Post Posted!"
    end
  end

  describe 'Post Show page' do
    let(:post){ Post.create title: 'Lazy-loaded Post', body: 'Body', user: user }
    before(:each){ visit "/posts/show/#{post.id}" }

    it "Post's title, body, and author are displayed" do
      expect(page).to have_content "#{post.title}"
      expect(page).to have_content "#{post.body}"
      expect(page).to have_content "#{post.user.name}"
    end
  end
end

controller:

PadrinoBlog::App.controllers :posts do

  get :new do
    @post = Post.new
    render 'posts/new'
  end

  post :create do
    post = Post.new(params[:post])
    post.user = current_user
    if post.save
      puts Post.all.count
      puts Post.last.inspect
      redirect('/posts', notice: "Post Posted!")
    end
  end

  get :index do
    @posts = Post.order('created_at DESC').all
    render 'posts/index'
  end

  get :show, with: :id do
    @post = Post.find_by_id(params[:id])
    render 'posts/show'
  end

end

index.html.erb:

<%= link_to "Sign Up", 'users/new' %>

<% unless signed_in? %>
  <%= link_to "Login", 'sessions/new' %>
<% end %>

<% if signed_in? %>
  <%= link_to "Logout", 'sessions/destroy' %>
<% end %>

<% if flash[:notice] %>
  <p><%= flash[:notice] %></p>
<% end %>

<% if signed_in? %>
  <%= link_to "Create Post", 'posts/new' %>
<% end %>

<% if @posts %>
  <%= partial 'posts/post', collection: @posts %>
<% end %>

_posts.html.erb:

<div class='post'>
  <h4><%= post.title %></h4>
  <p><%= post.body %></p>
  <p><%= post.user.name %></p>
</div>

When running the tests, the 'Show Page' test passes, but the first one (the long one) breaks when it clicks 'Create Post', with this:

Failure/Error: <p><%= post.user.name %></p>

     NoMethodError:
       undefined method `name' for nil:NilClass
     # ./app/views/posts/_post.html.erb:4:in `block in singleton class'
     # ./app/views/posts/_post.html.erb:-7:in `instance_eval'
     # ./app/views/posts/_post.html.erb:-7:in `singleton class'
     # ./app/views/posts/_post.html.erb:-9:in `__tilt_5665000'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/tilt-1.4.1/lib/tilt/template.rb:170:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/tilt-1.4.1/lib/tilt/template.rb:170:in `evaluate'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/tilt-1.4.1/lib/tilt/template.rb:103:in `render'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-helpers-0.13.1/lib/padrino/rendering/erb_template.rb:18:in `render'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:822:in `render'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-helpers-0.13.1/lib/padrino/rendering.rb:212:in `render'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-helpers-0.13.1/lib/padrino-helpers/render_helpers.rb:55:in `block in partial'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/activerecord-4.2.5/lib/active_record/relation/delegation.rb:132:in `each'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/activerecord-4.2.5/lib/active_record/relation/delegation.rb:132:in `each_with_object'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/activerecord-4.2.5/lib/active_record/relation/delegation.rb:132:in `public_send'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/activerecord-4.2.5/lib/active_record/relation/delegation.rb:132:in `method_missing'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/activerecord-4.2.5/lib/active_record/relation/delegation.rb:99:in `method_missing'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-helpers-0.13.1/lib/padrino-helpers/render_helpers.rb:48:in `partial'
     # ./app/views/posts/index.html.erb:20:in `block in singleton class'
     # ./app/views/posts/index.html.erb:-6:in `instance_eval'
     # ./app/views/posts/index.html.erb:-6:in `singleton class'
     # ./app/views/posts/index.html.erb:-8:in `__tilt_5665000'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/tilt-1.4.1/lib/tilt/template.rb:170:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/tilt-1.4.1/lib/tilt/template.rb:170:in `evaluate'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/tilt-1.4.1/lib/tilt/template.rb:103:in `render'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-helpers-0.13.1/lib/padrino/rendering/erb_template.rb:18:in `render'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:822:in `render'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-helpers-0.13.1/lib/padrino/rendering.rb:212:in `render'
     # ./app/controllers/posts.rb:20:in `block (2 levels) in <top (required)>'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/application/routing.rb:517:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/application/routing.rb:517:in `block in route'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/application/routing.rb:992:in `block in invoke_route'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/application/routing.rb:987:in `catch'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/application/routing.rb:987:in `invoke_route'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/application/routing.rb:952:in `block in route!'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/path_router/compiler.rb:53:in `block in call_by_request'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/path_router/compiler.rb:84:in `block in rotation'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/path_router/compiler.rb:83:in `loop'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/path_router/compiler.rb:83:in `with_object'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/path_router/compiler.rb:83:in `rotation'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/path_router/compiler.rb:49:in `call_by_request'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/path_router.rb:43:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/application/routing.rb:949:in `route!'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/application/routing.rb:932:in `block in dispatch!'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:1066:in `block in invoke'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:1066:in `catch'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:1066:in `invoke'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/application/routing.rb:930:in `dispatch!'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:906:in `block in call!'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:1066:in `block in invoke'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:1066:in `catch'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:1066:in `invoke'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:906:in `call!'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rspec-padrino-0.2.2/lib/rspec/padrino/initializers/last_application.rb:12:in `block (2 levels) in <top (required)>'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:894:in `call'
     # ./lib/connection_pool_management_middleware.rb:7:in `block in call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/activerecord-4.2.5/lib/active_record/connection_adapters/abstract/connection_pool.rb:292:in `with_connection'
     # ./lib/connection_pool_management_middleware.rb:7:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sass-3.4.21/lib/sass/plugin/rack.rb:54:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb:49:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-protection-1.5.3/lib/rack/protection/xss_header.rb:18:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb:49:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb:49:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-protection-1.5.3/lib/rack/protection/json_csrf.rb:18:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb:49:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-protection-1.5.3/lib/rack/protection/base.rb:49:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-protection-1.5.3/lib/rack/protection/frame_options.rb:31:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-1.6.4/lib/rack/head.rb:13:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-1.6.4/lib/rack/methodoverride.rb:22:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-1.6.4/lib/rack/session/abstract/id.rb:225:in `context'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-1.6.4/lib/rack/session/abstract/id.rb:220:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:2021:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:1486:in `block in call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:1795:in `synchronize'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/sinatra-1.4.6/lib/sinatra/base.rb:1486:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/router.rb:84:in `block in call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/router.rb:75:in `each'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/padrino-core-0.13.1/lib/padrino-core/router.rb:75:in `call'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-test-0.6.3/lib/rack/mock_session.rb:30:in `request'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rspec-padrino-0.2.2/lib/rspec/padrino/initializers/last_application.rb:34:in `block (2 levels) in <top (required)>'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-test-0.6.3/lib/rack/test.rb:244:in `process_request'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/rack-test-0.6.3/lib/rack/test.rb:58:in `get'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/capybara-2.6.0/lib/capybara/rack_test/browser.rb:60:in `process'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/capybara-2.6.0/lib/capybara/rack_test/browser.rb:38:in `block in process_and_follow_redirects'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/capybara-2.6.0/lib/capybara/rack_test/browser.rb:37:in `times'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/capybara-2.6.0/lib/capybara/rack_test/browser.rb:37:in `process_and_follow_redirects'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/capybara-2.6.0/lib/capybara/rack_test/browser.rb:26:in `submit'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/capybara-2.6.0/lib/capybara/rack_test/form.rb:77:in `submit'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/capybara-2.6.0/lib/capybara/rack_test/node.rb:61:in `click'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/capybara-2.6.0/lib/capybara/node/element.rb:134:in `block in click'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/capybara-2.6.0/lib/capybara/node/base.rb:84:in `synchronize'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/capybara-2.6.0/lib/capybara/node/element.rb:134:in `click'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/capybara-2.6.0/lib/capybara/node/actions.rb:13:in `click_link_or_button'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/capybara-2.6.0/lib/capybara/session.rb:686:in `block (2 levels) in <class:Session>'
     # /home/andrew/.rvm/gems/ruby-2.3.0/gems/capybara-2.6.0/lib/capybara/dsl.rb:51:in `block (2 levels) in <module:DSL>'
     # ./spec/features/posts_features_spec.rb:25:in `block (3 levels) in <top (required)>'
     # ./spec/spec_helper.rb:17:in `block (2 levels) in <top (required)>'

Like I said, no problems running locally in the browser, nothing breaks, but this test breaks, which is really strange, especially since the show view (which doesn't break) is:

<h4><%= @post.title %></h4>
<p><%= @post.body %></p>
<p><%= @post.user.name %></p>

I've even tried doing things without the partial in the index view, with:

<% @posts.each do |post| %>
  <h4><%= post.title %></h4>
  <p><%= post.body %></p>
  <p><%= post.user.name %></p>
<% end %>

...but I get exactly the same error. Wtf is going on?

I've pushed this present state to a commit here


Solution

  • Checking out your code and running the test I don't get the error, so I took a quick look at your migrations, and the last migration adds the user to the post. I'm guessing you have an issue with the DB in the test environment

    padrino rake ar:migrate:reset -e test
    

    should reset the DB and fix the issue