正确地覆盖体面曝光

时间:2011-06-24 02:59:52

标签: ruby-on-rails refactoring

Rails 3.0.7 + Decent Exposure Gem

我正在为具有一个关联属性的模型创建表单:

class Foo
  has_many :bars

  def self.build_next(attributes={})
    if item = last.try(:clone)
      # ... overrides
    else
      item = self.new
    end

    item.attributes = attributes
    return entry
  end
end

允许用户从选择框中选择一个相关项目。所以我的基本控制器看起来像这样:

class FooController < ApplicationController
  expose(:foos)
  expose(:foo)
  expose(:bar)

  def new
   #...
  end

  def create
    if foo.save
      redirect_to foo
    else
      render :action => 'new'
    end
  end
end

这很好用,但需要调整功能以克隆上一个项目而不是创建一个新项目。所以我补充说:

  default_exposure do |name|
    collection = name.to_s.pluralize
    if respond_to?(collection) && collection != name.to_s && send(collection).respond_to?(:scoped)
      proxy = send(collection)
    else
      proxy = name.to_s.classify.constantize
    end

    if id = params["#{name}_id"] || params[:id]
      proxy.find(id).tap do |r|
        r.attributes = params[name] unless request.get?
      end
    else

      # NEW CODE
      if name == :foo && params[:action] == :new.to_s
        # override
        Foo.build_next
      else
        proxy.new(params[name])
      end

    end
  end

这完全有效,但它几乎毁了我的乐趣。它超级巨大,令人难以置信的草率。必须有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

为什么不在模型的回调之前而不是在控制器中执行此操作?

e.g。

class Foo < ActiveRecord::Base
  has_many :bars
  before_validation_on_create :build_next
  def build_next
    if prev_item = Foo.last.try(:clone)
      # ... overrides
    else
      prev_item = Foo.new
    end

    attributes.reverse_merge! prev_item.attributes 
  end
end