SJK
SJK

Reputation: 135

link_to and the destroy method

I have an app where you add games (found via API) to a user's library, but I also want the user to delete games from a library. However I am not sure if I am using the correct link_to path or if the issue is with my controller.

Routes

Rails.application.routes.draw do
  get 'library_game/index'
  devise_for :users
  root to: 'pages#home'
  get '/games', to: 'games#index', as: :index
  get '/user/:id', to: 'user#show'
  resource :user, only: [] do
  resources :games, only: [:create, :destroy]
end
  get '/user/:id/library', to: 'library#index', as: :library
  post '/user/:id/library', to: 'games#create', as: :create
  delete 'user/:id/library', to: 'games#destroy', as: :destroy
end

My game model

class Game < ApplicationRecord
  has_many :library_games
  has_many :libraries, through: :library_games
  has_many :users, through: :libraries
  serialize :data
  attr_accessor :game_id

  def fetch_data
    game = GiantBomb::Game.detail(game_id)
    self.data = Hash[game.instance_variables.map { |var| [var.to_s[1..-1], game.instance_variable_get(var)] } ]
  end

  def to_giant_bomb_game
    GiantBomb::Game.new(data)
  end
end

My link_to for deleting:

<%= link_to 'Remove from library', destroy_path(current_user, game_id: game.id), method: :delete %>

My controller method for destroy:

def destroy
    current_user.games.where(game_id: params[:id]).destroy_all
    redirect_to library_path
  end

With what I have now, I am getting this error: ActiveRecord::StatementInvalid in GamesController#destroy PG::UndefinedColumn: ERROR: column games.game_id does not exist

So the error throws up an issue with the controller, but I am wondering if the real culprit is that my link_to is not passing the correct data. What should I be passing to my link_to?

Upvotes: 0

Views: 1278

Answers (2)

sam
sam

Reputation: 1161

If the connection is LibraryGame (as in it has a library_id and a game_id) then this

resource :user, only: [] do
  resources :games, only: [:create, :destroy]
end

needs to be

resources :users, only: [] do
  resources :library_games, only: [:create, :destroy], shallow: true
end

The shallow: true, gives you routes like users/1/library_games/x for index, create, and new, but routes like library_games/x for show, edit, update, and destroy. Best of both worlds.

And then your link would be <%= link_to "Remove from Library", library_game_path(library_game), method: :delete %>.

Upvotes: 1

Clara
Clara

Reputation: 2715

Check in your html (with the inspector tool in the browser) what link the link_to helper method is generating. You have 2 routes in routes.rb that deal with the deletion of games, but since your using destroy_path this is the one that's interesting:

 delete 'user/:id/library', to: 'games#destroy', as: :destroy

See how there is one placeholder for :id? This is the user id, not the game id, however in the destroy action in your controller you look for the game with params[:id] which is the user id

...(game_id: params[:id])...

And this is why it fails.

You need to clean up your routes. In the one above, why is the path user/:id/library but it goes to the games controller. Why is there another route above that deals with the deletion of games? In ruby on rails everything is about conventions, and you should follow them too. You also want to look into nested routing https://guides.rubyonrails.org/routing.html#nested-resources

For a destroy action you normally don't need to nest the route because with the id of the game you should be able to find it in the database and destroy it. Also you have devise so you can work with the current_user which you already do. So you could just have the route like this:

resources :games, only: :destroy

and then use the link_to method

<%= link_to 'Remove from library', game_path(game.id), method: :delete %>

Upvotes: 0

Related Questions