Почему мне нужно указывать:location=>some_url(@object) в response_with в случае POST

#ruby-on-rails #ruby-on-rails-4

#ruby-on-rails #ruby-on-rails-4

Вопрос:

Я реализую RESTful API с использованием RoR. Здесь мой UsersController :

 class ApplicationController < ActionController::API
    [...]
end

module Api
  module V1
    class UsersController < ApplicationController

      respond_to :json

      def create
        @user = User.new(user_params)
        @user.save
        respond_with @user, :location => api_v1_user_url(@user)
      end

      def show
        @user = User.find(params[:id])
        respond_with @user
      end

    end
  end
end
 

Если я опущу @user параметр из :location => api_v1_user_url(@user) in UsersController#create , т.Е. у меня это так:

 respond_with @user, :location => api_v1_user_url
 

Я получаю следующую ошибку:

 ActionController::UrlGenerationError in Api::V1::UsersController#create
No route matches {:action=>"show", :controller=>"api/v1/users", :format=>"json"} missing required keys: [:id]
 

Я просто добавил @user параметр в api_v1_user_url на догадке после того, как увидел эту ошибку, и она работает.

Мой вопрос в том, что здесь происходит? Я не понимаю, зачем мне нужно передавать @user , когда большинство примеров, которые я видел, не предполагают передачу объекта @user в :location атрибут.

Вывод rake routes является следующим:

 $ rake routes
Ignoring bcrypt-3.1.7 because its extensions are not built.  Try: gem pristine bcrypt-3.1.7
          Prefix Verb   URI Pattern                      Controller#Action
    api_v1_users GET    /api/v1/users(.:format)          api/v1/users#index {:format=>"json"}
                 POST   /api/v1/users(.:format)          api/v1/users#create {:format=>"json"}
 new_api_v1_user GET    /api/v1/users/new(.:format)      api/v1/users#new {:format=>"json"}
edit_api_v1_user GET    /api/v1/users/:id/edit(.:format) api/v1/users#edit {:format=>"json"}
     api_v1_user GET    /api/v1/users/:id(.:format)      api/v1/users#show {:format=>"json"}
                 PATCH  /api/v1/users/:id(.:format)      api/v1/users#update {:format=>"json"}
                 PUT    /api/v1/users/:id(.:format)      api/v1/users#update {:format=>"json"}
                 DELETE /api/v1/users/:id(.:format)      api/v1/users#destroy {:format=>"json"}
    static_index GET    /static/index(.:format)          static#index
            root GET    /                                static#index
 

Другое место, которое я видел (просто чтобы назвать другое):

Ответ №1:

Причина в том, что api_v1_user_url or api_v1_user_path предназначены для одного экземпляра, и вам нужно передать имя id этого пользователя, которое он должен искать и отображать. Следовательно, почему вы получили сообщение об ошибке.

В примерах, которые вы, вероятно, видели api_v1_users_url или api_v1_users_path которые отображают всех пользователей. Обратите внимание на users_ vs user_

Комментарии:

1. Это имеет смысл, но я не вижу упоминания о передаче id even в документах api здесь: api.rubyonrails.org/classes/ActionController/Responder.html

2. Идентификатор извлекается при передаче @user объекта, потому что действие show требует использования идентификатора (здесь также используется магия rails). Также, когда вы создаете каркас, в моем случае для Post model , вы получаете это: <%= link_to 'Show', post %> и <%= link_to 'Edit', edit_post_path(post) %> которые указывают, что при передаче объекта получается идентификатор.