【问题标题】:RSpec failure ( undefined method `id' for nil:NilClass ) with has_many through model通过模型使用 has_many 的 RSpec 失败(nil:NilClass 的未定义方法“id”)
【发布时间】:2016-05-08 13:31:17
【问题描述】:

我无法让规范传入关系控制器。我必须在控制器或 controller_spec 中更改有关我的对象的某些内容。 如有任何疑问,请随时询问我的控制器...谢谢

用户.rb

class User < ActiveRecord::Base

  # Associations
  has_many :active_relationships, class_name:  "Relationship",
                                  foreign_key: "follower_id",
                                  dependent:   :destroy
  has_many :passive_relationships, class_name:  "Relationship",
                                  foreign_key: "followed_id",
                                  dependent:   :destroy
  has_many :following, through: :active_relationships, source: :followed
  has_many :followers, through: :passive_relationships, source: :follower

  # Follows a user.
  def follow(other_user)
    active_relationships.create(followed_id: other_user.id)
  end

  # Unfollows a user.
  def unfollow(other_user)
    active_relationships.find_by(followed_id: other_user.id).destroy
  end

  # Returns true if the current user is following the other user.
  def following?(other_user)
    following.include?(other_user)
  end
end

用户规格:

require 'rails_helper'

RSpec.describe User, :type => :model do
  let(:user) { build(:user) }

  describe 'Validations' do
    it 'has a valid factory' do
      expect(user).to be_valid
    end

  let(:user) { create(:user) }
  let(:other_user) { create(:user) }

  describe '#following?' do
    it "expect relationship between two users to be empty" do
      expect(user.active_relationships).to be_empty
    end
  end

  describe '#follow' do
    it "creates the active relationship between two users" do
      user.follow(other_user)
      expect(user.active_relationships.first.followed_id).to eq(other_user.id)
    end

    it "creates the passive relationship between two users" do
      user.follow(other_user)
      expect(other_user.passive_relationships.first.follower_id).to eq(user.id)
    end
  end

  describe '#unfollow' do
    it "destroys the active relationship between two users" do
      user.follow(other_user)
      expect{
        user.unfollow(other_user)
      }.to change(Relationship, :count).by(-1)
    end
  end
end

relationship.rb

class Relationship < ActiveRecord::Base
  #Associations
  belongs_to :follower, class_name: "User"
  belongs_to :followed, class_name: "User"

#Validations
  validates :follower_id, presence: true
  validates :followed_id, presence: true
end

relationships_controller.rb

class RelationshipsController < InheritedResources::Base

  def create
    user = User.find(params[:followed_id])
    current_user.follow(user)
    redirect_to user
  end

  def destroy
    user = Relationship.find(params[:id]).followed
    current_user.unfollow(user)
    redirect_to user
  end
end

relationships_controller_spec.rb

require 'rails_helper'

describe RelationshipsController do
  let(:relationship) { create(:relationship) }
  let(:user) { create(:user) }

  before do
    sign_in :user, create(:user)
  end

  describe '#create' do
    let!(:followed) { create(:user) }
    it "should require logged-in user to create relationship" do
      expect{
        post :create, followed_id: followed.id
      }.to change(Relationship, :count).by(1)
      redirect_to root_path
    end
  end

  describe '#destroy' do
    let!(:relationship) { create(:relationship) }

    it "should require logged-in user to destroy relationship" do
      expect {
        delete :destroy, id: relationship.id
      }.to change(Relationship, :count).by(-1)
      redirect_to root_path
    end
  end
end

关系工厂:

FactoryGirl.define do
  factory :relationship do
    follower_id 1
    followed_id 1
  end
end

失败:

  1) RelationshipsController#destroy should require logged-in user to destroy relationship
     Failure/Error: active_relationships.find_by(followed_id: other_user.id).destroy

     NoMethodError:
       undefined method `id' for nil:NilClass

对于find 而不是find_by:

2) User#unfollow destroys the active relationship between two users
     Failure/Error: active_relationships.find(followed_id: other_user.id).destroy

     ActiveRecord::StatementInvalid:
       PG::UndefinedTable: ERROR:  missing FROM-clause entry for table "id"
       LINE 1: ...ips" WHERE "relationships"."follower_id" = $1 AND "id"."foll...
                                                                    ^
       : SELECT  "relationships".* FROM "relationships" WHERE "relationships"."follower_id" = $1 AND "id"."followed_id" = 36 LIMIT 1

【问题讨论】:

    标签: ruby-on-rails unit-testing testing rspec rspec-rails


    【解决方案1】:

    问题的根源是由于某种原因 Relationship.find(params[:id]).followed 返回 nil,导致后续行 current_user.unfollow(user) 向您提供您所看到的错误。

    您确定您的create(:relationship) 工厂在Relationship 中正确设置了followed 关联吗?

    另外,看看你的控制器规格,你定义 let!(:relationship) { create(:relationship) } 两次很奇怪。

    为什么不在规范的开头声明一个let!(:relationship) { create(:relationship) }(带有!)?

    最后,在unfollow 方法中使用find 而不是find_by 可能更合适,以防止在find_by(followed_id: other_user.id) 不存在的情况下在nil 上调用destroy。

    【讨论】:

    • 帖子已更新为工厂和relationships.rb。回答您的第一个问题:我认为是的,正如您在更新后的帖子中看到的那样。第二:谢谢你的建议,我已经更正了:)。第三,使用find 而不是find_by rspec 会报错,如上所示。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-27
    • 1970-01-01
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多