0

摘要

如何自定义respond_to为 ActiveModel 对象生成的路径?

更新:我正在寻找一个钩子、方法覆盖或配置更改来完成此操作,而不是解决方法。(解决方法很简单,但并不优雅。)

上下文和示例

这里有一个例子来说明。我有一个模型,Contract它有很多字段:

class Contract < ActiveRecord::Base
  # cumbersome, too much for a UI form
end

为了使 UI 代码更易于使用,我有一个更简单的类SimpleContract

class SimpleContract
  include ActiveModel::Model

  # ...

  def contract_attributes
    # convert SimpleContract attributes to Contract attributes
  end

  def save
    Contract.new(contract_attributes).save
  end
end

这很好用,但我的控制器有问题......

class ContractsController < ApplicationController
  # ...

  def create
    @contract = SimpleContract.new(contract_params)
    flash[:notice] = "Created Contract." if @contract.save
    respond_with(@contract)
  end

  # ...
end

问题是respond_with指向simple_contract_url我希望它指向contract_url。最好的方法是什么?(请注意,我使用的是 ActiveModel。)

(注意:我使用的是 Rails 4 Beta,但这不是我的问题的核心。我认为 Rails 3 的一个好的答案也可以。)

边栏:如果这种将模型包装在轻量级 ActiveModel 类中的方法对您来说不明智,请在评论中告诉我。就个人而言,我喜欢它,因为它使我的原始模型保持简单。“包装器”模型处理一些 UI 细节,这些细节被有意简化并提供合理的默认值。

4

2 回答 2

1

首先,这是一个有效的答案:

class SimpleContract
  include ActiveModel::Model

  def self.model_name
    ActiveModel::Name.new(self, nil, "Contract")
  end
end

我根据kinopyoChange input name of model的回答改编了这个答案。

现在,为什么。的调用堆栈respond_to有些涉及。

# Start with `respond_with` in `ActionController`. Here is part of it:

def respond_with(*resources, &block)
  # ...
  (options.delete(:responder) || self.class.responder).call(self, resources, options)
end

# That takes us to `call` in `ActionController:Responder`:

def self.call(*args)
  new(*args).respond
end

# Now, to `respond` (still in `ActionController:Responder`):

def respond
  method = "to_#{format}"
  respond_to?(method) ? send(method) : to_format
end

# Then to `to_html` (still in `ActionController:Responder`):

def to_html
  default_render
rescue ActionView::MissingTemplate => e
  navigation_behavior(e)
end

# Then to `default_render`:

def default_render
  if @default_response
    @default_response.call(options)
  else
    controller.default_render(options)
  end
end

这就是我目前所得到的。我实际上还没有找到构建 URL 的位置。我知道它是基于 发生的model_name,但我还没有找到它发生的代码行。

于 2013-04-10T22:09:59.177 回答
0

我不确定我是否完全理解你的问题,但你能做这样的事情吗?

class SimpleContract
  include ActiveModel::Model
  attr_accessor :contract

  # ...

  def contract_attributes
    # convert SimpleContract attributes to Contract attributes
  end

  def save
    self.contract = Contract.new(contract_attributes)
    contract.save
  end
end

-

class ContractsController < ApplicationController
  # ...

  def create
    @simple_contract = SimpleContract.new(contract_params)
    flash[:notice] = "Created Contract." if @simple_contract.save
    respond_with(@simple_contract.contract)
  end

  # ...
end

我可能离基地很远。希望这至少会为您触发一个想法。

于 2013-04-10T20:52:18.207 回答