Ruby on Rails with Interactors 已翻译 100%

oschina 投递于 2013/05/30 07:33 (共 4 段, 翻译完成于 06-01)
阅读 428
收藏 0

At FiveStreet, we have been focusing heavily on the 'Mise en place' of our objects ( thanks to Dave Bock for the phrase ). This has been key to our early success. We have found that focusing on the placement of objects allows us to worry more about building new features while adding less fear of breaking stuff. One of our strategies for achieving this is by using interactor objects.

Interactors can be defined as the use cases of your application, for example adding a comment. They are also a great place for objects that shouldn't know about each to interact. For example, in the following code example you will see that when adding a comment we also interact with a external object, the MixpanelWrapper object. What follows is a dead simple example of how we use them in our application.

已有 1 人翻译此段

Add a Comment Interactor:

  class Agent::AddComment
    attr_reader :comment
    def initialize(agent, comment)
      @agent = agent
      @comment = comment
    def allowed?
      touch_log = TouchLog.find(@comment.touch_log_id)
      return false if !@comment.valid? || touch_log.agent_id !=
      return true
    def run()
      return false if !allowed?
      MixpanelWrapper.track("Agent: Add Comment To Prospect", { :distinct_id => })


The previous chunk of code is a sample of how we build interactors. All of our interactors have two main methods,#allowed?and#run. In theallowed?method we handle all of our validations. Therunmethod runs the use case and more!

The Comment Controller

  class Agent::CommentsController < ApplicationController
    def create
      comment =[:comment])
      action =, comment)
        flash_success_on_redirect "Comment was added."
        redirect_to prospect_path(action.comment.touch_log)
        flash_error_on_redirect "Please enter a comment."
        redirect_to prospect_path(action.comment.touch_log)

This controller is pretty basic, the newish thing here is, comment)instead of the normalcomment =[:comment]);

已有 1 人翻译此段

At a high level what are the benefits:

  • Easy to Read/Understand: When I started looking at the code base for the first I knew exactly what was happening and where to find each use case.
  • Testing is easier: Thanks to the separation of concerns we gain.
  • Low 'learning' curve: There is nothing amazingly complex going on, you just pass the objects into the interactor and make the magic happen.

What are the negatives:

  • More files: Yeah there are more files but in the end it is easier to search.
  • More prep-time: It is not the default Rails way of doing things, but adding an extra file shouldn't be hard.

已有 1 人翻译此段

How does this add business value:

As mentioned we have been extremely happy with this approach and these are some of the main reasons:
  1. First, in a sense this reminds me of Rails. Interactors allow us to have such a great separation of concern that we are able to worry more about building new features and less about breaking shit. How so? Well each interactor lives on its own, it is separated from everything else.
  2. Being in its own world lets us easily remove code that we don't need. This is especially useful in the moments where that amazing new feature actually wasn't that amazing.
  3. It also allows us to reuse use-cases easier. If I wanted to post a comment anywhere else in the system I can just call this object again.
  4. Testing is 10 times easier, this is especially nice in those moments where you have a deadline and you don't have time to write the 'perfect' method. It's ok you got your test and you can always refactor.
  5. In the future when new people join the company their biggest requirement will be to know whatAgent::AddCommentis supposed to do?
已有 1 人翻译此段
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。