swilliams
swilliams

Reputation: 53

Deleting a record from a rails nested resource -- getting NoMethodError

I have two controllers: VendorsController and ServicesController. Vendors have services, and thus I've created nested routes:

#config/routes.rb
Rails.application.routes.draw do
  devise_for :users
  root "static_pages#index"
  get 'start', to: 'static_pages#start'
  resources :vendors do 
    resources :services
  end 
end

Services are listed on the vendor show page, and thus I want the user who owns the Vendor page to be able to delete a service (all from the vendor show page). Here is my code for this in the services controller:

#services_controller.rb
class ServicesController < ApplicationController
  before_action :authenticate_user!

# some more code

  def destroy
    @vendor = Vendor.find_by_id(params[:vendor_id])
    @service = Service.find_by_id(params[:id])
    if @service.user == current_user
      @service.destroy
      redirect_to vendor_path(@vendor), notice: "The service has been deleted."
    else
      return render text: 'Not Allowed', status: :forbidden
    end 
  end 
end 

And in vendor/show.html.erb:

<% current_vendor.services.each do |service| %>
   <% if current_vendor.user == current_user %>
      <%= link_to "Edit Service", edit_vendor_service_path(service), class: 'btn btn-primary float-right'%> 
      <%= link_to "Delete Service", vendor_service_path(current_vendor), method: :delete, data: {confirm: 'Are you sure? This action cannot be reversed.'}, class: 'btn btn-danger float-right'%>
   <% end %>
<% end %>

Note that current_vendor is a helper method. The problem is that this code passes in my rspec test suite, but in practice, I get the error "NoMethodError in ServicesController#destroy. undefined method `user' for nil:NilClass". After fiddling using pry, I realize the only way I could get it to work in practice is through changing the destroy method in my Services controller to this:

 def destroy
    @vendor = Vendor.find_by_id(params[:id])
    @service = Service.find_by_id(params[:vendor_id])
    if @service.user == current_user
      @service.destroy
      redirect_to vendor_path(@vendor), notice: "The service has been deleted."
    else
      return render text: 'Not Allowed', status: :forbidden
    end 
 end 

Once I do this, of course my rspec tests fail. This obviously doesn't make sense but I cannot figure out where I'm going wrong. Can anyone point out my mistake?

Upvotes: 0

Views: 50

Answers (1)

Sovalina
Sovalina

Reputation: 5609

You need the nested params of service in your destroy path :

<%= link_to "Delete Service", vendor_service_path(current_vendor, service), method: :delete %>

Your first version of destroy method should work this way.

Upvotes: 1

Related Questions