Rspec - 试图理解nil:NilClass错误

时间:2016-04-20 16:26:27

标签: ruby-on-rails ruby rspec

我试图为已经实施的代码进行测试。我是单元测试和RSpec的新手,在我的生活中无法弄清楚这个错误。基本上,我试图验证JSON是否被发送到正确的端点。我想我已经创建了我需要的所有属性,但我不断得到同样的错误。这是错误和我的代码。它显然与从另一个模型表中包括城市有关,但我不确定它为什么抱怨?

这是测试。

ncap2 -s 'valf=double(valf)' nc_data.nc nc_data.nc

这是我的错误消息

require "rails_helper"

RSpec.describe "/api/retailers" do

describe "GET /api/retailers" do
it "Returns JSON for retailers" do

    location = Location.create!(
      city: "Portland",
      street_1: "Cherry",
      state: "Oregon",
      zip: "49490"
    )

  retailer = Retailer.create!(
    name: "Good Coffee Co.",
    description: "Hipster Good",
    image_url: "http://www.example.com/foo_bar.jpg",
  )

  get "/api/retailers.json"

  expect(response).to be_success
  json = JSON.parse(response.body)

  expect(json["name"]).to eql("Good Coffee Co.")
  expect(json["description"]).to eql("Hipster Good")
  expect(json["image_url"]).to eql("http://www.example.com/foo_bar.jpg")
  expect(json["city"]).to eql(location.city)
end
end
end

这是我的控制器

/api/retailers GET /api/retailers Returns JSON for retailers
 Failure/Error: location.city

 NoMethodError:
   undefined method `city' for nil:NilClass
 # ./app/models/retailer.rb:8:in `city'

这是我的模特

class Api::RetailersController < ApiController
 def index
  @retailers = Retailer.all
  render json: @retailers, methods: [:city]
 end
end

任何帮助都会很棒。我真的很难过这个问题。如果有任何其他信息是必要的,请告诉我

3 个答案:

答案 0 :(得分:1)

您的Retailer模型与location有关系。

你也有一个city方法,正在查看location

def city
  location.city
end

现在,它包含在您的控制器中:

render json: @retailers, methods: [:city]

现在,在测试中,您创建了locationretailer

location = Location.create!(
      city: "Portland",
      street_1: "Cherry",
      state: "Oregon",
      zip: "49490"
    )

  retailer = Retailer.create!(
    name: "Good Coffee Co.",
    description: "Hipster Good",
    image_url: "http://www.example.com/foo_bar.jpg",
  )

但这两者在任何方面都无关。

因此,在测试中,您向控制器的get操作发送了index个请求,

get "/api/retailers.json"

这会尝试获取零售商的city,这是上述方法。但请记住,该方法会尝试获取location.city

但是您的retailer没有location,因为它尚未与任何内容相关联......所以,location此处为nil

然后,当您在city(即零)上致电location时,您正在city上呼叫nil

这是错误的来源:

NoMethodError:
   undefined method `city' for nil:NilClass
 # ./app/models/retailer.rb:8:in `city'

编辑(修复):

在测试中添加创建为零售商位置的位置,如下所示:

location = Location.create!(
  city: "Portland",
  street_1: "Cherry",
  state: "Oregon",
  zip: "49490"
)

retailer = Retailer.create!(
  name: "Good Coffee Co.",
  description: "Hipster Good",
  image_url: "http://www.example.com/foo_bar.jpg",
  location: location # Add location as location here.
)

答案 1 :(得分:1)

city方法使用Retailer的位置,该位置未针对您创建的位置设置。

要解决此问题,只需将location关联分配给Retailer

即可
retailer = Retailer.create!(
    name: "Good Coffee Co.",
    description: "Hipster Good",
    image_url: "http://www.example.com/foo_bar.jpg",
    location: location
  )

答案 2 :(得分:1)

您实际上从未在零售商和地点之间建立关联。因此,当调用retailer#city时,位置为零。

您可能希望首先更改您的方法以优雅地处理nil,除非您的业务逻辑不允许没有位置的零售商:

class Retailer < ActiveRecord::Base
  has_one :location

  has_many :retailer_timeslots
  has_many :timeslots, through: :retailer_timeslots

  def city
    location.city if location
  end
end

更优雅的方法是使用Module#delegate

class Retailer < ActiveRecord::Base
  has_one :location

  has_many :retailer_timeslots
  has_many :timeslots, through: :retailer_timeslots

  delegate :city, to: :location, allow_nil: true
end

这应该将规格从破坏变为失败。

要修复规范,您需要设置两者之间的关系:

location = Location.create!(
  city: "Portland",
  street_1: "Cherry",
  state: "Oregon",
  zip: "49490"
)

retailer = Retailer.create!(
  name: "Good Coffee Co.",
  description: "Hipster Good",
  image_url: "http://www.example.com/foo_bar.jpg",
  location: location # !!!!!
)