0

在 Rails 3.2.8 中。如果你有这条路线:

  namespace :some_module do
    resources :some_models
  end

并且对应的 SomeModel 不在模块中,那么在 SomeModule::SomeModelsController 中如果指定位置为模型实例(如在创建中),那么它对 url 的假设将是错误的:

respond_with @some_model, location: @some_model

因为它将假设 url 是 some_model_instance_url 而不是 some_module_some_model_instance_url。

出于某种原因,当我试图变得棘手并对我认为在 create 方法中正确的 url 进行通用评估时(因为这是包含在控制器中的通用模块中):

respond_with @some_model, location: send("#{self.class.name.chomp('Controller').gsub('::','_').underscore.singularize}_url")

它导致:(No route matches {:action=>"show", :controller=>"some_module/some_models"}这是复数,所以没有路线)

这似乎有点令人困惑。

但只是在做:

respond_with @some_model

当控制器设置为通过 json 响应时:

respond_to :json

对我来说,返回一个 204 并没有指示创建的实例的 id,而且您似乎需要一些指示,其中包括一个 ID 供客户端使用它(在不返回 id 的情况下创建一些东西不是好的做法)。

在与模型不同的模块中的控制器的 create 方法中使用 respond_with 的正确方法是什么,我们想要返回创建对象 id 的一些指示?

4

1 回答 1

0

在控制器中,如果控制器和模型都不是模块,那么要指定可以使用的位置:

respond_with @some_model, location: @some_model

但是,控制器在不同的模块中,所以如果你在控制器的创建方法中这样做,它将尝试评估方法 some_model_url(id),但在控制器上定义的是 some_module_some_model_url(id)。

因此,您可以采取的一种方法是:

respond_with @some_model, location: some_module_some_model_url(@some_model.id)

对于包含在控制器中的通用模块,实例方法可能如下所示:

def initialize
  super
  qualified_controller_name = self.class.name.chomp('Controller')
  @model_class = qualified_controller_name.split('::').last.singularize.constantize
  @model_singular_name_url_method_name_sym = "#{qualified_controller_name.gsub('::','_').underscore.singularize}_url".to_sym
  class_eval "def #{@model_singular_name}(id); #{@model_singular_name_url_method_name_sym}(id); end"
end

def create
  @value = @model_class.new(...)
  @value.save
  respond_with @value, location: send(@model_singular_name_url_method_name_sym, @value.id)
end

这将在 Location 响应标头中将位置作为 url 返回,因此在您的规范测试中,它可能会在发布后执行此操作:

location = response.headers['Location']
# now check that location looks correct, etc.

但是,正如一位同事指出的那样,如果您定义以下内容,则不必指定位置:

def some_module_some_model_url(record)
  some_model_url(record)
end

所以,一般地添加这个:

class_eval "def #{@model_singular_name}_url(record); #{@model_singular_name_url_method_name_sym}(record); end"

然后你只需要:

def create
  @value = @model_class.new(...)
  @value.save
  respond_with @value
end
于 2012-10-12T17:55:23.267 回答