简体   繁体   中英

How to pass ID in delete :destroy in Rails?

It is super simple, yet I can't figure out how to make the test pass.

I have a friendships controller that I wanted to test (I am building Rails app similar to this railscast ). It works on localhost. This is the test that I created. POST #create passed.

require 'rails_helper'

RSpec.describe FriendshipsController, type: :controller do
  login_user

  before :each do
    @friend1 = FactoryGirl.create(:user)
  end

  describe "POST #Create" do
    it "adds new friend" do
      expect {
        post :create, params: { friend_id: @friend1.id}
      }.to change(Friendship, :count).by(1)
    end
  end

  describe "DELETE #destroy" do
    it "removes a friend =(" do
      expect {
        delete :destroy, id: @friend1.id
      }.to change(Friendship, :count).by(1)
    end
  end

end

This is the actual controller:

class FriendshipsController < ApplicationController
  def create
    @friendship = current_user.friendships.build(friend_id: params[:friend_id])
    if @friendship.save
      flash[:notice] = "New friend added!"
      redirect_to root_url
    else
      flash[:error] = "Error adding friend"
      redirect_to root_url
    end
  end

  def destroy
    @friendship = current_user.friendships.find(params[:id])
    @friendship.destroy
    flash[:notice] = "Remove friendship"
    redirect_to current_user
  end
end

I also made sure that routes.rb have Friendships: resources :friendships

The problem I am having is to pass the ID.I can't figure out how to pass the id params. I think it has something to do with my factory...?

  1) FriendshipsController DELETE #destroy removes a friend =(
     Failure/Error: @friendship = current_user.friendships.find(params[:id])

     ActiveRecord::RecordNotFound:
       Couldn't find Friendship with 'id'=159 [WHERE "friendships"."user_id" = $1]

I search for other SO destroy related posts, like this one , this , but they are different case from mine.

How can I pass down ID params for my destroy action?

EDIT: ( Source )

module ControllerMacros
  def login_user
    before(:each) do
      @request.env["devise.mapping"] = Devise.mappings[:user]
      user = FactoryGirl.create(:user)
      #user.confirm! # or set a confirmed_at inside the factory. Only necessary if you are using the "confirmable" module
      sign_in user
    end
  end
end

As suggested by answer below, I did:

describe "DELETE #destroy" do
    it "removes a friend =(" do
      friendship = user.friendships.create!(friend_id: @friend1.id)
      expect {
        delete :destroy, id: friendship.id
      }.to change(Friendship, :count).by(1)
    end
  end

But it is now returning this error:

FriendshipsController DELETE #destroy removes a friend =(
     Failure/Error: friendship = user.friendships.create!(friend_id: @friend1.id)

     NameError:
       undefined local variable or method `user' for #<RSpec::ExampleGroups::FriendshipsController::DELETEDestroy:0x007fee1ce68c70>

As you're looking for the friendship, not the user in the controller, you need to create the friendship first. Before that you also need to know the user to be logged in. Try sending that first:

module ControllerMacros
  def login_user(user)
    before(:each) do
      @request.env["devise.mapping"] = Devise.mappings[:user]
      user ||= FactoryGirl.create(:user)
      sign_in user
    end
  end
end

Now the test would look something like this:

let(:current_user) { FactoryGirl.create(:user) }
login_user(current_user)

describe "DELETE #destroy" do
  it "removes a friend =(" do
    friendship = current_user.friendships.create!(friend_id: @friend1.id)
    expect {
      delete :destroy, id: friendship.id
    }.to change(Friendship, :count).by(1)
  end
end

You should be good to go now.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM