0

まとめ

respond_toActiveModel オブジェクト用に生成されるパスをカスタマイズするにはどうすればよいですか?

更新:回避策ではなく、これを達成するためのフック、メソッドのオーバーライド、または構成の変更を探しています。(回避策は簡単ですが、エレガントではありません。)

コンテキストと例:

以下に例を示します。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、代わりに を指すようにしたいです。それを行う最善の方法は何ですか?(ActiveModel を使用していることに注意してください。)contract_url

(注: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

私はこの回答をkinopyo's answerからChange 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 に答える