Jony
Jony

Reputation: 157

Rspec delete object failure with method has_many throw, No route matches {:action=>"destroy"

Need some help to make rspec test to pass, my goal is to delete a relationship that has been created with the method has_many throw. I followed this MHartl's tutorial.

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

routes.rb :

Rails.application.routes.draw do
  devise_for :users, controllers: { sessions: "users/sessions" }
  devise_for :admin_users, ActiveAdmin::Devise.config

  ActiveAdmin.routes(self)

  mount Peek::Railtie => '/peek'

  resources :users do
    member do
      get :following, :followers
    end
  end
  resources :relationships, only: [:create, :destroy]

  root to: "records#index"
end

user.rb:

class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable,
         :validatable, :confirmable, :timeoutable

  # 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

Factory:

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

Failures:

1) Relationships GET /relationships works! (now write some real specs)
     Failure/Error: get relationships_path

     ActionController::RoutingError:
       No route matches [GET] "/relationships"

  2) 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

Upvotes: 0

Views: 323

Answers (1)

Vasfed
Vasfed

Reputation: 18454

Your route for destroy is /relationships/:id and controller destroys the relation, but instead of passing relation's :id you're passing :followed_id, so indeed there's no such route.

So you can either modify your routes and controller or to make current code work change to:

delete :destroy, id: relationship.id

(you may then get an error about relationship not having a user, depending on factory)

Upvotes: 1

Related Questions