<commit_before># Focused Controller: Bringing Real OOP to Rails Controllers. #

[![Build Status](https://secure.travis-ci.org/jonleighton/focused_controller.png?branch=master)](http://travis-ci.org/jonleighton/focused_controller)


## Description ##

Classical Rails controllers violate the Single Responsibility Principle.

Each different "action" has separate responsibilities. A `create`
action does something entirely different to a `destroy` action, yet
they end up lumped into the same object.

This has three unfortunate side effects:

1. *We end up using instance variables to share data with our views when
   we should really be using methods*. Using instance variables for this
   purpose makes it harder to change your implementation and can lead to
   subtle bugs. For example, referencing an undeclared instance variable
   in a view will work, when it should probably raise an error. We could
   define public methods in our controllers and access those in our views,
   but this will quickly get unmaintainable.

2. *We misuse `before_filter`s to share functionality between actions*.
   Instead of using proper OO patterns like inheritance and mixins to keep
   our code DRY, we shoe-horn `before_filter` with `:only` or `:except` to
   share chunks of code between actions.

3. *Testing controllers actions is slow and unit testing them is hard*.
   Because classical Rails controller actions are bound to 
   ActionController::Base, you can only test them by excersinng the full
   framework stack. This is both very slow and unnecessary. You should be
   able to write simple unit tests that just exercice the actual behaviour
   of your actions, and rely on your acceptance/integration tests to test
   the full stack.

Focused Controller aims to address these issues by making controllers actions
like any other object. That means they:

* Only have one reason to change.
* Are easy to instantiate and test in issolation.

## Feedback needed ##

This project is in early stages, and while I have been using it
successfully on a production application, I'm very keen for others to
start experimenting with it and providing feedback.

Note that I will follow SemVer, and the project is currently pre-1.0, so
there could be API changes. However if the user base grows significantly,
then I will try to avoid painful changes.

## Usage ##

Focused Controller changes Rails' conventions. Rather than controllers
being objects which contain one method per action, controllers are now
simply namespaces and each action is a class within that namespace.
Controllers which wish to use this convention simply include the
`FocusedController::Mixin` module. This means that you can start using
Focused Controller in an existing project without having to rewrite all
your existing controller code.

An example:

``` ruby
module PostsController
  # Action is as a common superclass for all the actions
  # inside `PostsController`.
  class Action < ApplicationController
    include FocusedController::Mixin
  end

  class Index < Action
    def run
      # your code here
    end

    # No instance variables are shared with the view. Instead,
    # public methods are defined.
    def posts
      @posts ||= Post.all
    end

    # To prevent yourself having to write `controller.posts`
    # in the view, you can declare the method as a helper
    # method which means that calling `posts` automatically
    # delegates to the controller.
    helper_method :posts
  end

  # Actions do not need to declare a `run` method - the default
  # implementation inherited from `FocusedController::Mixin` is an
  # empty method.
  class Show < Action
    def post
      @post ||= Post.find params[:id]
    end
    helper_method :post
  end
end
```

## Routing ##

Rails' routing assumes your actions are methods inside an object whose
name ends with 'controller'. For example:

``` ruby
get '/posts/new' => 'posts#new'
```

will route `GET /posts/new` to `PostsController#new`.

To get around this, we use the `focused_controller_routes` helper:

``` ruby
focused_controller_routes do
  get '/posts/new' => 'posts#new'
end
```

The route will now map to `PostsController::New#run`.

This is similar to writing:

``` ruby
get '/posts/new' => proc { |env| PostsController::New.call(env) }
```

All the normal routing macros are supported:

``` ruby
focused_controller_routes do
  resources :posts
end
```

## Functional Testing ##

Though it's not encouraged, focused controllers can be tested in the
classical 'functional' style. This can be a useful interim measure when
converting a controller to be properly unit tested.

It no longer makes sense to specify the action name to be called as the
action name is always "run". So this is omitted:

``` ruby
module UsersController
  class CreateTest < ActionController::TestCase
    include FocusedController::FunctionalTestHelper

    test "should create user" do
      assert_difference('User.count') do
        post user: { name: 'Jon' }
      end

      assert_redirected_to user_path(@controller.user)
    end
  end
end
```

There is also an equivalent helper for RSpec:

``` ruby
describe UsersController do
  include FocusedController::RSpecFunctionalHelper

  describe UsersController::Create do
    it "should create user" do
      expect { post user: { name: 'Jon' } }.to change(User, :count).by(1)
      response.should redirect_to(user_path(subject.user))
    end
  end
end
```

## Unit Testing ##

A better way to test your controllers is with unit tests. This involves
creating an instance of your action object and calling methods on it. For
example, to test that your `user` method finds the correct user, you
might write:

``` ruby
module UsersController
  class ShowTest < ActiveSupport::TestCase
    test 'finds the user' do
      user = User.create

      controller = UsersController::Show.new
      controller.params = { id: user.id }

      assert_equal user, controller.user
    end
  end
end
```

### The `#run` method ###

Testing the code in your `#run` method is a little more involved,
depending on what's in it. For example, your `#run` method may use
(explicitly or implicitly) any of the following objects:

* request
* response
* params
* session
* flash
* cookies
<commit_msg>More minor tweaks<commit_after># Focused Controller: Bringing Real OOP to Rails Controllers #

[![Build Status](https://secure.travis-ci.org/jonleighton/focused_controller.png?branch=master)](http://travis-ci.org/jonleighton/focused_controller)


## Description ##

Classical Rails controllers violate the Single Responsibility Principle.

Each different "action" has separate responsibilities: A `create`
action does something entirely different to a `destroy` action, yet
they end up lumped into the same object.

This has three unfortunate side effects:

1. *We end up using instance variables to share data with our views when
   we should really be using methods*. Using instance variables for this
   purpose makes it harder to change your implementation and can lead to
   subtle bugs. For example, referencing an undeclared instance variable
   in a view will work, when it should probably raise an error. We could
   define public methods in our controllers and access those in our views,
   but this will quickly get unmaintainable.

2. *We misuse before_filters to share functionality between actions*.
   Instead of using proper OO patterns like inheritance and mixins to keep
   our code DRY, we shoe-horn `before_filter` with `:only` or `:except` to
   share chunks of code between specific actions.

3. *Testing controller actions is slow and unit testing them is hard*.
   Because classical Rails controller actions are bound to 
   ActionController::Base, you can only test them by excersinng the full
   framework stack. This is both very slow and unnecessary. You should be
   able to write simple unit tests that just exercice the actual behaviour
   of your actions, relying on your acceptance/integration tests to exercise
   the full stack.

Focused Controller aims to address these issues by making controllers actions
like any other object. That means they:

* Only have one reason to change.
* Are easy to instantiate and test in issolation.

## Feedback needed ##

This project is in early stages, and while I have been using it
successfully on a production application, I'm very keen for others to
start experimenting with it and providing feedback.

Note that I will follow SemVer, and the project is currently pre-1.0, so
there could be API changes. However if the user base grows significantly,
then I will try to avoid painful changes.

## Usage ##

Focused Controller changes Rails' conventions. Rather than controllers
being classes that contain one method per action, controllers are now
simply namespaces and each action is a class within that namespace.
Controllers which wish to use this convention simply include the
`FocusedController::Mixin` module. This means that you can start using
Focused Controller in an existing project without having to rewrite all
your existing controller code.

An example:

``` ruby
module PostsController
  # Action is a common superclass for all the actions
  # inside `PostsController`.
  class Action < ApplicationController
    include FocusedController::Mixin
  end

  class Index < Action
    def run
      # your code here.
    end

    # No instance variables are shared with the view. Instead,
    # public methods are defined.
    def posts
      @posts ||= Post.all
    end

    # To prevent yourself having to write `controller.posts`
    # in the view, you can declare the method as a helper
    # method which means that calling `posts` automatically
    # delegates to the controller.
    helper_method :posts
  end

  # Actions do not need to declare a `run` method - the default
  # implementation inherited from `FocusedController::Mixin` is an
  # empty method.
  class Show < Action
    def post
      @post ||= Post.find params[:id]
    end
    helper_method :post
  end
end
```

## Routing ##

Rails' normal routing assumes your actions are methods inside an object
whose name ends with 'controller'. For example:

``` ruby
get '/posts/new' => 'posts#new'
```

will route `GET /posts/new` to `PostsController#new`.

To get around this, we use the `focused_controller_routes` helper:

``` ruby
focused_controller_routes do
  get '/posts/new' => 'posts#new'
end
```

The route will now map to `PostsController::New#run`.

This is similar to writing:

``` ruby
get '/posts/new' => proc { |env| PostsController::New.call(env) }
```

All the normal routing macros are also supported:

``` ruby
focused_controller_routes do
  resources :posts
end
```

## Functional Testing ##

Though it's not encouraged, focused controllers can be tested in the
classical 'functional' style. This can be a useful interim measure when
converting a controller to be properly unit tested.

It no longer makes sense to specify the action name to be called as the
action name is always "run". So this is omitted:

``` ruby
module UsersController
  class CreateTest < ActionController::TestCase
    include FocusedController::FunctionalTestHelper

    test "should create user" do
      assert_difference('User.count') do
        post user: { name: 'Jon' }
      end

      assert_redirected_to user_path(@controller.user)
    end
  end
end
```

There is also an equivalent helper for RSpec:

``` ruby
describe UsersController do
  include FocusedController::RSpecFunctionalHelper

  describe UsersController::Create do
    it "should create user" do
      expect { post user: { name: 'Jon' } }.to change(User, :count).by(1)
      response.should redirect_to(user_path(subject.user))
    end
  end
end
```

## Unit Testing ##

A better way to test your controllers is with unit tests. This involves
creating an instance of your action class and calling methods on it. For
example, to test that your `user` method finds the correct user, you
might write:

``` ruby
module UsersController
  class ShowTest < ActiveSupport::TestCase
    test 'finds the user' do
      user = User.create

      controller = UsersController::Show.new
      controller.params = { id: user.id }

      assert_equal user, controller.user
    end
  end
end
```

### The `#run` method ###

Testing the code in your `#run` method is a little more involved,
depending on what's in it. For example, your `#run` method may use
(explicitly or implicitly) any of the following objects:

* request
* response
* params
* session
* flash
* cookies

{'fraction_non_alphanumeric': 0.0654011804115489, 'fraction_numerical': 0.000957090445047057, 'mean_word_length': 3.9230467216332943, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 9, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '999008', 'n_tokens_mistral': 3383, 'n_tokens_neox': 3207, 'n_words': 1625}