【问题标题】:Refactor this controller?重构这个控制器?
【发布时间】:2011-09-24 18:58:19
【问题描述】:
class ArticlesController < ApplicationController

  def index
    @articles = Article.by_popularity

    if params[:category] == 'popular'
      @articles = @articles.by_popularity
    end

    if params[:category] == 'recent'
      @articles = @articles.by_recent
    end

    if params[:category] == 'local'
      index_by_local and return
    end

    if params[:genre]
      index_by_genre and return
    end

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @articles }
    end
  end

  def index_by_local
    # 10 lines of code here

    render :template => 'articles/index_by_local'
  end

  def index_by_genre
    # ANOTHER 10 lines of code here

    render :template => 'articles/index_by_genre'
  end
end

从上面可以看到。我的控制器并不完全。它的作用是,根据传递的参数,它与模型交互以过滤掉记录。

如果 params[:local]params[:genre] 已通过。然后分别调用自己的方法(def index_by_localdef index_by_genre)做进一步处理。这些方法还加载自己的模板,而不是 index.html.erb

这对于控制器来说是不是很典型?或者我应该以某种方式重构它?

【问题讨论】:

    标签: ruby-on-rails-3 refactoring


    【解决方案1】:

    我们可以将前几行移到模型中(article.rb):

    def get_by_category(category)
      # Return articles based on the category.
    end
    

    这样我们就可以完全用单元测试来测试文章获取逻辑了。

    通常将所有与获取模型内的记录相关的代码移动。 一般控制器

    1. 应该授权用户
    2. 使用参数获取记录并将它们分配给实例变量 [这些通常必须是功能 调用模型]
    3. 渲染或重定向

    【讨论】:

      【解决方案2】:

      我将为您要使用的每个集合定义范围。

      class Article < ActiveRecord::Base
        ...
        scope :popular, where("articles.popular = ?", true) # or whatever you need
        scope :recent, where(...)
        scope :by_genre, where(...)
        scope :local, where(...)
        ...
      
        def self.filtered(filter)
          case filter
          when 'popular'
            Article.popular, 'articles/index'
          when 'recent'
            Article.recent, 'articles/index'
          when 'genre'
            Article.by_genre, 'articles/index_by_genre'
          when 'local'
            Article.local, 'articles/index_by_local'
          else
            raise "Unknown Filter"
          end
        end
      end
      

      然后在你的控制器动作中,像这样:

      def index
        @articles, template = Article.filtered(params[:category] || params[:genre])
        respond_to do |format|
          format.html { render :template => template }
          format.xml  { render :xml => @articles }
        end
      end
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-06-11
        • 2013-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多