CChandler81
CChandler81

Reputation: 347

Rails integration test - undefined method for nil:NilClass - works in prod

I'm working my way through Michael Hartl's tutorial (with a few custom additions so I learn more) and am running into the following error during a run of my test despite it seemingly working fine in production. Each user can have multiple relatives.

RelativesNewTest#test_valid_submission:

app/views/relatives/show.html.erb:38:in 'block in _app_views_relatives_show_html_erb__4581323407307698757_68563600'

app/views/relatives/show.html.erb:30:in '_app_views_relatives_show_html_erb__4581323407307698757_68563600'

test/integration/relatives_new_test.rb:47:in 'block in class:RelativesNewTest'

The Relative model:

class Relative < ApplicationRecord
  belongs_to :user
  has_one :state
  has_one :relation

  validates :user_id, :name, presence: true

The State and Relation tables have only id and name columns.

The Relative controller:

class RelativesController < ApplicationController
  before_action :setup

  def setup
    @user = current_user
    @relatives = current_user.relatives.all
  end

  def index
  end

  def show
  end

  def new
    @relative = Relative.new
  end

  def create
    @relative = current_user.relatives.build(relative_params)
    if @relative.save
      redirect_to relatives_path
    else
      render 'new'
    end
  end

  def edit
    @relative = current_user.relatives.find(params[:id])
  end

  def update
    @relative = current_user.relatives.find(params[:id])
    if @relative.update_attributes(relative_params)
      redirect_to relatives_path
    else
      render 'edit'
    end
  end

  def destroy
    @relative = current_user.relatives.find(params[:id])
    @relative.destroy
    flash[:success] = "Relative deleted"
    redirect_to relatives_path
  end

  private

  def relative_params
    params.require(:relative).permit(:name, :relation_id, :email, :phone, :street, :unit, :city, :state_id, :zip)
  end
end

The view:

<% @relatives.each do |relative| %>
  <div id="relative_<%= relative.id %>" class="row row-lines">
    <div class="col-md-2 col-sm-4 col-xs-12 form-group">
      <p id="name" class="form-control"><%= relative.name %></p>
    </div>
    <div class="col-md-1 col-sm-2 col-xs-12 form-group">
      <p id="relation" class="form-control">
      <% unless relative.relation_id.nil? %>
        <%= Relation.find_by_id(relative.relation_id).name %>
      <% end %></p>
    </div>

The lines that are referenced in the error are <% @relatives.each do |relative| %> and <%= Relation.find_by_id(relative.relation_id).name %>. This all (show, new, edit) works fine in production.

The test:

require 'test_helper'

class RelativesNewTest < ActionDispatch::IntegrationTest

  def setup
    @user = users(:testuser)
  end

  test "valid submission" do
    log_in_as(@user)
    get relatives_new_path
    assert_difference 'Relative.count', 1 do
      post relatives_new_path params: {relative: {
        name: 'First Relative',
        relation_id: 1,
        street: '123 Fake Street',
        city: 'Philadelphia',
        state_id: 39,
        zip: 12345}}
    end
    assert_not flash.empty?
    assert_redirected_to relatives_path
    follow_redirect!
    assert_select 'p#name', 'First Relative'
  end
end

The line from the test that is referenced in the error is follow_redirect!. The view works fine in production, showing the associated Relation name. Is there something unique about redirects and variables in tests that I have to account for?

Upvotes: 0

Views: 258

Answers (1)

vitomd
vitomd

Reputation: 806

I think that in your test you need to create a Relation with id 1 (before you post relatives_new_path) as you have a reference to it in your Relative creation.

name: 'First Relative',
relation_id: 1,

Or you can do something like

relation = new Relation
log_in_as(@user)
get relatives_new_path
assert_difference 'Relative.count', 1 do
  post relatives_new_path params: {relative: {
    name: 'First Relative',
    relation_id: relation.id,

Upvotes: 1

Related Questions