1

我一直在 Rails 代码中看到这一点:

before filter :get_post, only: [:edit, :update, :destroy]

def edit
  # code .......
end

def update
  # code .......
end

def destroy
  # code .......
end

private
  def get_post
    @post = Post.find(params[:id])
  end

我知道它不会重复同一行代码三次,但是通过将代码重构为私有方法而不隐藏实例变量和之前的过滤器,没有更容易阅读和更好的方法来完成同样的事情?

private
  def get_post(post_id)
    Post.find(post_id)
  end

然后您可以将实例变量保留在操作中

def edit
  @post = get_post(params[:id])
end

在私有方法中隐藏实例变量在概念上没有意义。为什么这在 Rails 中如此普遍?

4

5 回答 5

3

你可能会看到很多关于这种特殊做法的不同意见。就个人而言,我同意你的看法;我觉得严格遵守 DRY 只会通过在文件底部的方法中隐藏实例变量来引入一些混乱。我什至不确定一种get_post方法是否真的能帮您买很多东西。也就是说,在许多情况下,我更喜欢明确性(如果这是一个词)而不是简洁性,并且对于在每个控制器中始终使用此技巧的团队来说,可能不会有那么多(如果有的话)混乱。

如果过滤器封装了更多的复杂性,它可能是值得的。例如,Ryan Bates 的流行授权库CanCan引入了一个控制器类宏,称为load_and_authorize_resource安装before_filters,以便自动加载 RESTful 资源并授权当前用户访问。每个方法可能不止一行或两行,并且不会每次都逐字重复。

一些 Rails 开发人员使用一种流行的中间立场,即将 指定before_filter为块,因此您不必重复自己,但实例变量位于文件顶部:

before_filter(only: [:edit, :update, :destroy]) do
  @post = Post.find(params[:id])
end

正如评论中所提到的,有一些 gem,比如decent_exposure,它们有助于形式化这种模式并使其显着减少“隐藏”或混淆(因为它是明确声明的并且 API 是已知的)。

于 2013-05-14T05:23:04.770 回答
2

正如其他人所说,这是一个见仁见智的问题。我开始使用 before 过滤器来隐藏控制器之间的公共实例变量。有时我仍然会这样做,但我发现这是控制器臃肿的代码气味。如果您有太多实例变量需要将它们隐藏在过滤器中,那么您做的太多了。我的观点是控制器动作应该非常小,如果所有动作都有一条共同的线来处理实例变量,那不是问题。

为了让我的控制器动作达到一个让我对拥有一个公共实例变量感到满意的水平,我的补救措施是使用服务对象/呈现器将曾经在几个实例变量中的信息整合到每个控制器动作的单个实例变量中。我发现这大大提高了我的控制器和视图的可读性和可维护性。

于 2013-05-14T05:37:05.433 回答
1

我认为您的建议是对典型 Rails 约定的改进。不过,我会更进一步,完全删除实例变量。使用实例变量会产生误导,因为它通常不代表多个控制器操作之间的共享状态,而且通常甚至不会在任何方法之间共享(分配它的 before 过滤器除外)。

填充实例变量以在视图中使用的 Rails 约定是一个坏主意,它的使用应该消失。在一个干净的 MVC 实现中,控制器中的任何内容都不会在视图中可用。我认为这是一个更清晰的实现,可以正确地分离各层:

def edit
  post = get_post(params[:post_id])
  render 'edit', locals: { post: post }
end

没有泄漏状态,不依赖视图中的实例变量,明确的意图,以及更容易重用的视图,并且可以从其他视图中呈现,而无需注入 hacky 内联实例变量赋值。

Rails 有许多用于快速引导的约定,但它们并不能生成好的代码。

于 2013-05-14T06:03:17.513 回答
0

还有另一种方法使用helper_method. 它看起来几乎如你所愿。

http://rails-bestpractices.com/posts/57-substituting-before_filter-load_object

于 2013-05-14T06:06:54.190 回答
0

这是对配置的约定。

这两种方法都没有错,但喜欢 Ruby 的人通常更喜欢极简的编码模式,并且重视使用最快的方法来解决问题,这样他们就可以继续解决更复杂和有趣的问题

如果您经常看到这种方法使用得足够多,那么在定义代码之前让所有成员函数(显然不是集合函数)为您预加载成员变量将成为第二天性。它达到了在函数中指定成员变量不会产生显着的清晰度优势(如果有的话)的地步。

于 2013-05-14T05:33:09.317 回答