Rails:NoMethodError(用于_controller的未定义方法_url.创建后似乎无法正确响应json.为什么? [英] Rails: NoMethodError (Undefined method _url for _controller. I can't seem to respond_with json properly after my create. Why?

查看:92
本文介绍了Rails:NoMethodError(用于_controller的未定义方法_url.创建后似乎无法正确响应json.为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  1. 列表项

我的config/routes.rb文件...

My config/routes.rb file...

Rails.application.routes.draw do

  namespace :api, defaults: {format: 'json'} do
    namespace :v1 do
      resources :hotels do
        resources :rooms
      end
    end
  end

我的app/controllers/api/v1/hotels_controller.rb

My app/controllers/api/v1/hotels_controller.rb

module Api
    module V1
        class HotelsController < ApplicationController
            respond_to :json
            skip_before_filter :verify_authenticity_token

            def index
                @hotels = Hotel.all
                respond_with ({hotels: @hotels}.as_json)
                #respond_with(@hotels)
            end

            def show
                @hotel = Hotel.find(params[:id])
                respond_with (@hotel)
            end

            def create
                @hotel = Hotel.new(user_params)
                if @hotel.save
                    respond_with (@hotel) #LINE 21
                end
            end

            private

                def user_params
                    params.require(:hotel).permit(:name, :rating)
                end
        end
    end
end

当我通过Postman进行POST时,我的数据保存得很好,但是却收到此NoMethodError.为什么是这样?问题似乎发生在第21行,这是response_with(@hotel)行.不仅应该通过show方法使用新创建的酒店的json ouput进行响应吗?

When I go to POST through Postman, my data saves just fine, but I get this NoMethodError. Why is this? The issue seems to be occurring at line 21, which is the respond_with(@hotel) line. Should it not just be responding with json ouput for the newly created hotel, via the show method?

(1.1ms)  COMMIT
Completed 500 Internal Server Error in 76ms

NoMethodError (undefined method `hotel_url' for #<Api::V1::HotelsController:0x0000010332df58>):
  app/controllers/api/v1/hotels_controller.rb:21:in `create'


  Rendered /Users/.rvm/gems/ruby-2.0.0-p451@railstutorial_rails_4_0/gems/actionpack-4.1.0/lib/action_dispatch/middleware/templates/rescues/_source.erb (1.0ms)
  Rendered /Users/.rvm/gems/ruby-2.0.0-p451@railstutorial_rails_4_0/gems/actionpack-4.1.0/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (1.7ms)
  Rendered /Users/.rvm/gems/ruby-2.0.0-p451@railstutorial_rails_4_0/gems/actionpack-4.1.0/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (1.4ms)
  Rendered /Users/.rvm/gems/ruby-2.0.0-p451@railstutorial_rails_4_0/gems/actionpack-4.1.0/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (31.5ms)

推荐答案

由于您的路由位于API + v1命名空间中,因此您实际上需要在成功创建资源后重定向到api_v1_hotel_url(@hotel).当然,这是一个API,并且没有真正的重定向,但是默认的Rails响应器不知道这一点.它还不知道您的路由名称空间.

Because your route is in the API + v1 namespace, you actually need to redirect to the api_v1_hotel_url(@hotel) after you successfully create your resource. Of course, this is an API and there is no real redirecting, but the default Rails responder doesn't know that. It also doesn't know about your routing namespaces.

仅使用默认响应者,您就必须这样做

With just the default responder, you would have to do

respond_with :api, :v1, @hotel

因此,Rails将构建一个存在的URL.或者,您可以创建一个删除:location选项的自定义响应器.这是默认的响应者: http://api.rubyonrails.org /files/actionpack/lib/action_controller/metal/responder_rb.html

So that Rails will build a URL that exists. Alternatively, you can create a custom responder that remove the :location option. Here is the default responder: http://api.rubyonrails.org/files/actionpack/lib/action_controller/metal/responder_rb.html

通读该类的源代码对于理解respond_with很有帮助.例如,在此响应器上使用respond_with之前,无需使用if record.save. Rails将检查记录是否为您成功保存,如果保存失败,则呈现422错误.

Reading through the source code for that class is very helpful in understanding respond_with. For example, you don't need to use if record.save before you use respond_with with this Responder. Rails will check if the record saved successfully for you and render a 422 with errors if it failed to save.

无论如何,您可以看到响应者在其初始值设定项中设置了很多变量:

Anyway, you can see that the responder sets up a lot of variables in it's initializer:

def initialize(controller, resources, options={})
  @controller = controller
  @request = @controller.request
  @format = @controller.formats.first
  @resource = resources.last
  @resources = resources
  @options = options
  @action = options.delete(:action)
  @default_response = options.delete(:default_response)
end

如果您将此响应程序子类化,则可以进行如下操作:

If you subclassed this responder, you could make something like this:

class CustomResponder < ActionController::Responder
  def initialize(*)
    super
    @options[:location] = nil
  end
end

您可以使用responder=设置控制器的响应者:

You can set a controller's responder using responder=:

class AnyController < ActionController::Base
  self.responder = CustomResponder

  # ...
end

为清楚起见,让我回顾一下:

To be clear, let me recap:

  1. 使用respond_with时,Rails将在成功创建后尝试推断要重定向到的路由.想象一下,您有一个Web UI,可以在其中创建酒店.创建酒店后,您将被重定向到标准Rails流中该酒店的show页面.这就是Rails在这里要做的.
  2. Rails在推断路线时不理解您的路线名称空间,因此会尝试hotel_url-一条不存在的路线!
  3. 在资源前面添加符号将使Rails正确推断路线,在这种情况下为api_v1_hotel_url
  4. 在API中,您可以创建一个自定义响应器,该响应器仅将推断的位置设置为nil,因为您实际上不需要通过简单的JSON响应重定向到任何地方.自定义响应者也可以在许多其他方式中有用.查看源代码.
  1. When you use respond_with, Rails will try to infer what route to redirect to after a successful create. Imagine you had a web UI where you can create hotels. After a hotel is created, you will be redirected to that hotel's show page in the standard Rails flow. That is what Rails is trying to do here.
  2. Rails does not understand your route namespaces when inferring the route, so it attempts hotel_url - a route which does not exist!
  3. Adding symbols in front of the resource will allow Rails to infer the route correctly, in this case api_v1_hotel_url
  4. In an API, you can make a custom responder which just sets the inferred location to nil, since you don't actually need to redirect anywhere with a simple JSON response. Custom responders can also be useful in many other ways. Check out the source code.

这篇关于Rails:NoMethodError(用于_controller的未定义方法_url.创建后似乎无法正确响应json.为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆