干涸开始救援结束

时间:2012-07-02 12:05:14

标签: ruby-on-rails ruby design-patterns

我有这个创建方法:

def create
    ...
    grid = Tag.find_by_id(story[:tag_id]) or raise GridNotFoundError
    ...
    event = Event.find_by_id(story[:event_id]) or raise EventNotFoundError
    ...
  rescue GridNotFoundError
    flash.now[:error] = "Please select a category"
    @item = item
    @years = story[:years]
    @event_name = race[:name]
    @country = race[:country]
    @classification = race[:class]
    @events = Event.all
    @countries = Tag.countries
    @classifications = Classification.all
    @grids = Tag.grids.find(:all, :conditions => ["value != ?", "Channel Creation Grid"])
    render "home/race_updates"
  rescue EventNotFoundError
    flash.now[:error] = "Please select an event or create a new one if you don't find your event"
    @item = item
    @event = story[:event_id]
    @years = story[:years]
    @events = Event.all
    @countries = Tag.countries
    @classifications = Classification.all
    @grids = Tag.grids.find(:all, :conditions => ["value != ?", "Channel Creation Grid"])
    render "home/race_updates"
  rescue CreateEventError
    flash.now[:error] = "There has been a problem creating your event."
    params[:expand] = true
    @item = item
    @years = story[:years]
    @event_name = race[:name]
    @country = race[:country]
    @classification = race[:class]
    @events = Event.all
    @countries = Tag.countries
    @classifications = Classification.all
    @grids = Tag.grids.find(:all, :conditions => ["value != ?", "Channel Creation Grid"])
    render "home/race_updates"
  rescue ActiveRecord::RecordNotSaved, ActiveRecord::RecordInvalid, ActiveRecord::RecordNotFound
    flash.now[:error] = item.errors.full_messages.join(" ,")
    @item = item
    @event = story[:event_id]
    @years = story[:years]
    @events = Event.all
    @countries = Tag.countries
    @classifications = Classification.all
    @grids = Tag.grids.find(:all, :conditions => ["value != ?", "Channel Creation Grid"])
    render "home/race_updates"
  end

如您所见,救援工作几乎相同。救援也是家庭#race_updates方法的文字复制贴。

我有两个问题:

  1. 我有什么方法可以干这个吗?
  2. 这对控制器来说这是一个很好的模式吗?
  3. 我想过把它作为一个功能分开,但我需要传递flash消息,项目,故事和竞赛变量。我觉得它不是一个优雅的解决方案,但肯定会更清洁。

    我发现以这种方式编码(即提出错误并挽救它们)使我更容易将实际业务逻辑分离,并处理业务中出现的不同错误/案例逻辑。到目前为止,它是有效的,但我想收集意见,如果这是最佳做法,或者我没有按照预期使用开始/救援?

3 个答案:

答案 0 :(得分:4)

如果你能这样做的话,干这个是一个好主意,也是铁轨设计(和测试驱动开发/ TDD)的一个很好的教训。

理想情况下,你会做这样的事情:

def create
    ...
    grid = Tag.find_by_id(story[:tag_id]) or raise GridNotFoundError
    ...
    event = Event.find_by_id(story[:event_id]) or raise EventNotFoundError
    ...
  rescue GridNotFoundError
    flash.now[:error] = "Please select a category"
    process_grid_not_found(item, story, race, etc...)
  rescue EventNotFoundError
    flash.now[:error] = "Please select an event or create a new one if you don't find your event"
    process_event_not_found(item, story, race, etc...)
  rescue CreateEventError
    flash.now[:error] = "There has been a problem creating your event."
    process_event_create_error(item, story, race, etc...)
  rescue ActiveRecord::RecordNotSaved, ActiveRecord::RecordInvalid, ActiveRecord::RecordNotFound
    flash.now[:error] = item.errors.full_messages.join(" ,")
    process_other_error(item, story, race, etc...)
  end
  render 'home/race_updates'

然后你应该在模型中将相关的新方法(process_event_not_found等)创建为单独的(可能是private)方法。

这既使代码更具可读性,又具有很大的优势,更容易编写测试代码。

那么你应该编写测试代码(使用Test::Unitrspec或其他)来测试每个异常方法所需的隔离功能。您会发现,这既可以产生更好的代码,也可以将异常方法分解为更小,更模块化的方法本身。

当您听到Ruby和Rails开发人员谈论测试驱动开发的好处时,该方法的主要好处之一是它不太可能导致像您在这里获得的那样长而复杂的方法。更可能的是,你的代码更干净,使用更小,更简单的方法。

我还建议,一旦你完成了这个,你再看看,并尝试进一步简化它。将有更多的简化空间,但我建议迭代地重构它,然后在我描述并开始测试的同时将其分解开始。

答案 1 :(得分:1)

我将Kevin Bedell的回答与Victor Moroz的见解以及and and or in Ruby are flow control structures的事实相结合。我想出了这个:

def create
    ...
    grid = Tag.find_by_id(story[:tag_id]) or (render_race_updates(item, "Please select a category") and return)
    ...
    event = Event.find_by_id(story[:event_id]) or (render_race_updates(item, "Please select an event or create a new one if you don't find your event") and return)
    ...
    if item.save
      ...
    else
      render_race_updates item, item.errors.full_messages.join(", ")
    end
  rescue CreateEventError
    params[:expand] = true
    render_race_updates item, "There has been a problem creating your event."
  end
private
  def render_race_updates(item, message)
    flash.now[:error] = message
    # etc.
    render "home/race_updates"
  end

通过这种方式,我可以处理它出现的异常情况,而不会引发异常,同时捕获其他方法冒出的异常。

但是,我还没有写测试。现在,我只写单元测试。仍然受到RSpec的影响并慢慢地将我的“翼展”发展改为TDD,但这是一次完全不同的对话。

答案 2 :(得分:-2)

如果它仍然100%正确,你必须自己验证这一点,因为我可能错过了一些东西,但也许这就是你要找的东西?

def create
    ...
    grid = Tag.find_by_id(story[:tag_id]) or raise GridNotFoundError
    ...
    event = Event.find_by_id(story[:event_id]) or raise EventNotFoundError
    ...
rescue Exception => e
    flash.now[:error] = e.is_a?(GridNotFoundError) ? "Please select a category" :
                        e.is_a?(EventNotFoundError) ? "Please select an event or create a new one if you don't find your event" : 
                        e.is_a?(CreateEventError) ? "There has been a problem creating your event." :
                        e.is_a?(ActiveRecord::RecordNotSaved) or e.is_a?(ActiveRecord::RecordInvalid) or e.is_a?(ActiveRecord::RecordNotFound) ? item.errors.full_mesages.join(", ") : e.to_s
    @item = item
    @years = story[:years]
    @event_name = race[:name] unless e.is_a?(EventNotFoundError) or e.is_a?(ActiveRecord::RecordNotSaved) or e.is_a?(ActiveRecord::RecordInvalid) or e.is_a?(ActiveRecord::RecordNotFound)
    @events = Event.all
    @countries = Tag.countries
    @classifications = Classification.all
    @grids = Tag.grids.find(:all, :conditions => ["value != ?", "Channel Creation Grid"])
    @event = story[:event_id] if e.is_a?(EventNotFoundError) or e.is_a?(ActiveRecord::RecordNotSaved) or e.is_a?(ActiveRecord::RecordInvalid) e.is_a?(ActiveRecord::RecordNotFound)

    if e.is_a?(GridNotFoundError) or e.is_a?(CreateEventError) 
        @country = race[:country]
        @classification = race[:class]

    end

    params[:expand] = true if e.is_a?(CreateEventError)

    render "home/race_updates"
end