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?

查看:17
本文介绍了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

我的应用/控制器/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 行,即 respond_with(@hotel) 行.它不应该只是通过 show 方法为新创建的酒店响应 json 输出吗?

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天全站免登陆