如何 DRY 在所有操作中都相同的 respond_to?

how to DRY a respond_to that is the same in all actions?

我有一个控制器可以为小部件提供服务:

class WidgetsController < ApplicationController
  def widget1
    respond_to do |format|
      format.html
      format.js { render js: js_constructor }
    end
  end

  def widget2
    respond_to do |format|
      format.html
      format.js { render js: js_constructor }
    end
  end

  private
  def js_constructor
    content = render_to_string(params[:action], layout: false)
    "document.write(#{content.to_json})"
  end
end

这个控制器会变大,所以我想避免在所有操作中重复这段代码:

respond_to do |format|
  format.html
  format.js { render js: js_constructor }
end

有什么想法吗?

编辑:只是为了提供一些背景...

路线是flexible/dynamic:get 'widgets/:action', to: 'widgets#:action'

因此,如果我访问 widgets/widget1,它将呈现视图 widget1.html.erb

如果我将脚本包含在另一台服务器中,它将在那里构建 widget1:

<script type='text/javascript' src='http://localhost:3000/widgets/widget1.js'></script>

答案是元编程:

class WidgetsController < ApplicationController
  [:widget1, :widget2].each do |name|
    define_method(name) do
      respond_to do |format|
        format.html
        format.js { render js: js_constructor }
      end
    end
  end

  private

  def js_constructor
    content = render_to_string(params[:action], layout: false)
    "document.write(#{content.to_json})"
  end
end

我会编写一个将 "view" 作为参数的动作。您基本上是在执行呈现不同视图的 #show 操作。

get 'widgets/:template', to: 'widgets#show'

class WidgetsController < ApplicationController
  def show
    respond_to do |format|
      format.html { render params.require(:template) }
      format.js { render js: js_constructor }
    end
  end

  private
  def js_constructor
    content = render_to_string(params.require(:template), layout: false)
    "document.write(#{content.to_json})"
  end
end