在过滤器中隐藏实例变量是不好的风格?

时间:2013-05-14 05:08:59

标签: ruby-on-rails

我一直在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

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

5 个答案:

答案 0 :(得分:3)

你可能会看到很多关于这种特殊做法的不同意见。 个人,我同意你的意见;我觉得严格遵守DRY只会通过隐藏文件底部方法中的实例变量来引入一些混乱。我甚至不确定get_post方法真的非常适合你。也就是说,在许多情况下,我更倾向于使用显性(如果这是一个词),而且对于在每个控制器中始终如一地使用此技巧的团队,可能没有那么多(如果有的话)混淆。

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

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

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

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

答案 1 :(得分:2)

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

我将控制器操作设置为让我对使用公共实例变量感到满意的级别的补救措施是使用服务对象/演示者将每个控制器操作中的多个实例变量中的一次信息合并到单个实例变量中。我发现这对我的控制器和视图的可读性和可维护性有了很大的改进。

答案 2 :(得分:1)

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

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

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

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

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

答案 3 :(得分:0)

这是一个关于配置事物的约定。

这两种方法都不对,但喜欢Ruby的人往往更喜欢极简主义的编码模式,并且使用最快的方法来解决问题,以便他们能够解决更复杂和有趣的问题

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

答案 4 :(得分:0)

使用helper_method还有另一种方法。它几乎就像你想要的那样。

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