重构这个控制器?

发布于 2024-11-17 12:48:27 字数 1115 浏览 0 评论 0原文

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

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

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

As you can see from above. My controller is not exactly thin. What its doing is, depending on the params that were passed, it interacts with the model to filter out records.

And if params[:local] or params[:genre] was passed. Then it calls its own methods respectively (def index_by_local and def index_by_genre) to do further processing. These methods also load their own template, instead of index.html.erb.

Is this quite typical for a controller to look? Or should I be refactoring this somehow?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

歌枕肩 2024-11-24 12:48:27

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

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

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

一般来说,将与获取模型内的记录相关的所有代码移至模型中。
一般来说,控制器

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

We can move the first few lines into the model(article.rb):

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

In this way we can completely test the article fetching logic using unit tests.

In general move all the code related to fetching records inside model.
Controllers in general

  1. should authorize the user
  2. get records using the params and assign them to instance variables
    [These must typically be function
    calls to model]
  3. Render or redirect
披肩女神 2024-11-24 12:48:27

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

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

I would define scopes for each of the collections you want to use.

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

Then in your controller action, something like this:

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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文