Reputation: 135
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
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
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