问题
I'm working on a rails 4 API for a sports team where I have players and teams and I'm struggling a little with rails routing and a has_many
relationship. My relationship between players and teams looks like:
class Team < ActiveRecord::Base
extend Searchable
validates :title, presence: true
has_and_belongs_to_many :players
end
class Player < ActiveRecord::Base
extend Searchable
validates :first_name, presence: true
validates :last_name, presence: true
has_and_belongs_to_many :teams
end
I'd like to be able to add an existing player to a team, but I'm unsure of how to change my routes.rb
file. Currently, it looks like:
Rails.application.routes.draw do
devise_for :users
namespace :api, defaults: { format: :json },
constraints: { subdomain: 'api' }, path: '/' do
scope module: :v1 do
resources :users, :only => [:show, :create, :update, :destroy]
resources :teams, :only => [:show, :create, :update, :destroy, :index]
resources :players, :only => [:show, :create, :update, :destroy, :index]
resources :sessions, :only => [:create, :destroy]
end
end
end
which allows for CRUD operations on players and teams models. I was thinking that for adding a player to an existing team, my route would need to look like:
/teams/:team_id/add_player/
but I'm unsure of how to declare that route in routes.rb
. So, a couple of questions:
- Does that route make sense to people from a REST-ful perspective? If so, how would I declare this route in
routes.rb
- Should it be a PATCH or a POST method for adding a player to a team?
Thanks for any help offered,
Sean
回答1:
You can declare this route like this:
resources :teams, only: [:show, :create, :update, :destroy, :index] do
put 'add_player', on: :member
end
It will map the route to the add_player
action in your TeamsController
.
From the REST-ful perspective i would suggest you to make this in the players#update
action though, since you are basically changing the player record.
回答2:
You'll need to use a nested resource:
#config/routes.rb
resources :teams, only: [....] do
resources :players, path: "", path_names: {new: "add_player", create: "add_player", destroy: "remove_player" }, only: [:create, :destroy] #-> /v1/teams/:team_id/add_player
end
This will route to your players_controller
, passing the :team_id
param:
#app/controllers/players_controller.rb
class PlayersController < ApplicationController
def new
@players = Player.all
end
def create
if params[:team_id]
@team = Team.find params[:team_id]
@player = Player.find params[:id]
@team.players << player
else
# normal "create" action
end
end
def destroy
if params[:team_id]
@team = Team.find params[:id]
@player = Player.find params[:id]
@team.players.delete player
end
end
end
You'd be able to couple this with the following view:
#app/views/players/new.html.erb
<%= form_tag team_players_path do %> #-> method should be "post"
<%= collection_select :player, :id, @players, :id, :name %>
<%= submit_tag %>
<% end %>
--
Trivia:
With HABTM, you get the << & collection.delete
methods -- both allowing you to add and remove objects from a collection super simply.
-
Does that route make sense to people from a REST-ful perspective? If so, how would I declare this route in
routes.rb
Yep.
Should it be a PATCH or a POST method for adding a player to a team?
In line with the resourceful routing structure, I'd say you could get away with a POST
request to the create
action, but it could be done a number of ways!
Update
Do this:
#config/routes.rb
resources :teams, only: [....] do
match "players/:id", to: "players", via: [:put, :delete]
end
This will create the following routes:
#put url.com/teams/:team_id/players/:id
#destroy url.com/teams/:team_id/players/:id
This will allow you to use a players
method in your teams
controller:
#app/controllers/teams_controller.rb
class TeamsController < ApplicationController
def players
@team = Team.find params[:team_id]
@player = Player.find params[:id]
if request.put?
@team.players << player
elsif request.delete?
@team.players.destroy player
end
end
end
来源:https://stackoverflow.com/questions/33364584/rails-routing-for-has-and-belongs-to-many-relationship