简体   繁体   English

Rails:清理难看的控制器

[英]Rails: Cleaning up ugly controllers

I'm all for the skinnier controller, fatter model mindset. 我全力支持更瘦的控制器,更胖的模型思维方式。

I wanted to know how to go about: 我想知道如何去做:

  1. How you identify things that should be moved to your model (assuming you're like me and you get lazy and need to refactor your controllers because you just shove code in there) 如何确定应移至模型的事物(假设您像我一样,并且变得懒惰,并且需要重构控制器,因为您只是在其中推入了代码)

  2. How you write and structure the creation of new elements in your controller. 您如何在控制器中编写和组织新元素的创建。 See following example. 请参见以下示例。

Example

I had a relatively messy controller for a polymophic "vote". 我有一个相对混乱的控制器,用于多词“表决”。 I've cleaned it up pretty well, but I wanted to know if I could improve this action a little better: 我已经很好地清理了它,但是我想知道是否可以更好地改进此操作:

def up
 vote = Vote.new
 vote.vote = true
 vote.voter = current_user    
 vote.voteable = Recipe.find params[:id]
 vote.save
end

To me it's just a little ugly, and I probably should just use create instead of new, but I'm wondering if I'm driving down a deadly path here by using a non-standard action (concerning REST). 对我来说,这有点丑陋,我可能应该只使用create而不是new,但是我想知道我是否正在通过使用非标准操作(关于REST)来推动这条致命的道路。

I'm working on switching it to new right now. 我正在努力将其切换为new But I definitely wanted to get the point of view of the community about. 但是我绝对想了解社区的观点。

The key to this is Test-Driven Development. 关键是测试驱动开发。 Once you make it a habit, the question of where to put code is answered for you 95% of the time. 一旦养成习惯,就会在95%的时间为您回答在哪里放置代码的问题。 Here's why. 这就是为什么。

Unit testing (model testing in Rails) is the easiest place to test code. 单元测试(Rails中的模型测试)是测试代码最容易的地方。 Model methods should be unit tested "black box" style - meaning you don't care what's inside the method, only that input X provides output Y. This will also cause you to write a greater number of smaller methods in your model, instead of very large methods. 模型方法应该经过单元测试的“黑匣子”样式-意味着您不在乎方法内部是什么,只不过输入X提供了输出Y。这也将导致您在模型中编写大量较小的方法,而不是非常大的方法。 The easier it is to test, the better - and not just for testing's sake. 测试越容易,就越好-而且不仅仅是为了测试。 Simpler methods are easier to override by other code, which is a big advantage of Ruby. 更简单的方法更易于被其他代码覆盖,这是Ruby的一大优势。

Controller (functional) tests, on the other hand, will find you caring more about what happens inside the action, since those methods aren't cut and dry input/output scenarios. 另一方面,控制器(功能)测试将使您更关心动作内部发生的事情,因为这些方法并不是多余的,而且不会浪费输入/输出场景。 Database calls happen, session variables are set, etc. Shoulda is a great test suite that automates a lot of this for you. 发生数据库调用,设置会话变量,等等。Shoulda是一个很棒的测试套件,可以自动为您执行很多操作。

Finally, my advice is to look inside some of your favorite plugins to see how they're doing things. 最后,我的建议是查看一些您喜欢的插件,以了解它们的运行情况。 And if you're interested more in testing, I have an article about restful controller tests in Shoulda that might get you started. 而且,如果您对测试有更多的兴趣,我会在《 Shoulda》上发表有关静态控制器测试的文章这可能会让您入门。

In RESTful controllers, especially with a lot of actions I sometimes create a before_filter to load the object: 在RESTful控制器中,尤其是通过大量操作,有时我会创建一个before_filter来加载对象:

before_filter :load_recipe, :only => %w(show edit update destroy up down)

private
def load_recipe
  @recipe = Recipe.find(params[:id])
end

In your case I might consider moving voting to the user model so you would have something like: 在您的情况下,我可能会考虑将投票移至用户模型,因此您将遇到以下情况:

def up
  current_user.vote(@recipe)
end

And then in your model: 然后在您的模型中:

class User < ActiveRecord::Base
  has_many :votes

  def vote(object)
    votes.create(:vote => true, :voteable => object)
  end
end

The benefit of that is that you can easily test the behavior of voting in isolation, and it can be re-used if there are other places you might want to enable voting (voting as in implicit result of another action, voting via API, mass-voting, etc). 这样做的好处是,您可以轻松地单独测试投票的行为,并且如果您想在其他地方启用投票功能,则可以重新使用它(如其他操作的隐式结果,通过API投票,大量投票一样) -投票等)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM