带有has_many到模型的RSpec失败(nil:NilClass的未定义方法`id')

时间:2016-05-08 13:31:18

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

我无法使规范传递给关系控制器。我必须在控制器或controller_spec中更改有关我的对象的内容。 随意对我的控制器提出任何疑问......谢谢

user.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

user_spec:

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

1 个答案:

答案 0 :(得分:1)

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

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

此外,查看您的控制器规范,您将两次定义let!(:relationship) { create(:relationship) }很奇怪。

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

最后,在find方法中使用find_by代替unfollow可能更合适,以防止在{{{}}上调用destroy 1}}不存在。