Skip to content

Commit

Permalink
Add support for custom default controller configuration (#788)
Browse files Browse the repository at this point in the history
* Add configure functionality to allow customizing the default.

* Add configuration module and tests.

* Add documentation to the README.md

* Skip tests that only fail when whole suite is ran.

* Fix the double leaking by re-writing the test that caused the issue.

* Clean up railtie - Exract out method, Remove unnecessary compatibility.

* Add new functionality to the dummy app to increase test coverage.
  • Loading branch information
Cliff Braton committed Mar 31, 2017
1 parent 2e6f741 commit ff36bd8
Show file tree
Hide file tree
Showing 13 changed files with 85 additions and 31 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,6 +368,18 @@ you'll have access to an ArticleDecorator object instead. In your controller you
can continue to use the `@article` instance variable to manipulate the model -
for example, `@article.comments.build` to add a new blank comment for a form.

## Configuration
Draper works out the box well, but also provides a hook for you to configure its
default functionality. For example, Draper assumes you have a base `ApplicationController`.
If your base controller is named something different (e.g. `BaseController`),
you can tell Draper to use it by adding the following to an initializer:

```ruby
Draper.configure do |config|
config.default_controller = BaseController
end
```

## Testing

Draper supports RSpec, MiniTest::Rails, and Test::Unit, and will add the
Expand Down
3 changes: 3 additions & 0 deletions lib/draper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
require 'active_support/core_ext/name_error'

require 'draper/version'
require 'draper/configuration'
require 'draper/view_helpers'
require 'draper/delegation'
require 'draper/automatic_delegation'
Expand All @@ -27,6 +28,8 @@
require 'draper/railtie' if defined?(Rails)

module Draper
extend Draper::Configuration

def self.setup_action_controller(base)
base.class_eval do
include Draper::ViewContext
Expand Down
15 changes: 15 additions & 0 deletions lib/draper/configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Draper
module Configuration
def configure
yield self
end

def default_controller
@@default_controller ||= ApplicationController
end

def default_controller=(controller)
@@default_controller = controller
end
end
end
29 changes: 11 additions & 18 deletions lib/draper/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
module ActiveModel
class Railtie < Rails::Railtie
generators do |app|
app ||= Rails.application # Rails 3.0.x does not yield `app`

Rails::Generators.configure! app.config.generators
require_relative '../generators/controller_override'
end
Expand All @@ -13,7 +11,6 @@ class Railtie < Rails::Railtie

module Draper
class Railtie < Rails::Railtie

config.after_initialize do |app|
app.config.paths.add 'app/decorators', eager_load: true

Expand All @@ -23,46 +20,42 @@ class Railtie < Rails::Railtie
end
end

initializer "draper.setup_action_controller" do |app|
initializer 'draper.setup_action_controller' do
ActiveSupport.on_load :action_controller do
Draper.setup_action_controller self
end
end

initializer "draper.setup_action_mailer" do |app|
initializer 'draper.setup_action_mailer' do
ActiveSupport.on_load :action_mailer do
Draper.setup_action_mailer self
end
end

initializer "draper.setup_orm" do |app|
initializer 'draper.setup_orm' do
[:active_record, :mongoid].each do |orm|
ActiveSupport.on_load orm do
Draper.setup_orm self
end
end
end

initializer "draper.minitest-rails_integration" do |app|
initializer 'draper.minitest-rails_integration' do
ActiveSupport.on_load :minitest do
require "draper/test/minitest_integration"
require 'draper/test/minitest_integration'
end
end

console do
def initialize_view_context
require 'action_controller/test_case'
ApplicationController.new.view_context
Draper.default_controller.new.view_context
Draper::ViewContext.build
end

runner do
require 'action_controller/test_case'
ApplicationController.new.view_context
Draper::ViewContext.build
end
console { initialize_view_context }

rake_tasks do
Dir[File.join(File.dirname(__FILE__),'tasks/*.rake')].each { |f| load f }
end
runner { initialize_view_context }

rake_tasks { Dir[File.join(File.dirname(__FILE__), 'tasks/*.rake')].each { |f| load f } }
end
end
3 changes: 2 additions & 1 deletion lib/draper/view_context/build_strategy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ def call
attr_reader :block

def controller
(Draper::ViewContext.controller || ApplicationController.new).tap do |controller|
Draper::ViewContext.controller ||= Draper.default_controller.new
Draper::ViewContext.controller.tap do |controller|
controller.request ||= new_test_request controller if defined?(ActionController::TestRequest)
end
end
Expand Down
25 changes: 25 additions & 0 deletions spec/draper/configuration_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require 'spec_helper'

module Draper
RSpec.describe Configuration do
it 'yields Draper on configure' do
Draper.configure { |config| expect(config).to be Draper }
end

it 'defaults default_controller to ApplicationController' do
expect(Draper.default_controller).to be ApplicationController
end

it 'allows customizing default_controller through configure' do
default = Draper.default_controller

Draper.configure do |config|
config.default_controller = CustomController
end

expect(Draper.default_controller).to be CustomController

Draper.default_controller = default
end
end
end
9 changes: 4 additions & 5 deletions spec/draper/view_context/build_strategy_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@ module Draper

context "when a current controller is not set" do
it "uses ApplicationController" do
view_context = fake_view_context
stub_const "ApplicationController", double(new: fake_controller(view_context))
strategy = ViewContext::BuildStrategy::Full.new

expect(strategy.call).to be view_context
expect(Draper::ViewContext.controller).to be_nil
view_context = ViewContext::BuildStrategy::Full.new.call
expect(view_context.controller).to eq Draper::ViewContext.controller
expect(view_context.controller).to be_an ApplicationController
end
end

Expand Down
4 changes: 0 additions & 4 deletions spec/dummy/app/controllers/application_controller.rb

This file was deleted.

4 changes: 4 additions & 0 deletions spec/dummy/app/controllers/base_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class BaseController < ActionController::Base
include LocalizedUrls
protect_from_forgery
end
2 changes: 1 addition & 1 deletion spec/dummy/app/controllers/posts_controller.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class PostsController < ApplicationController
class PostsController < BaseController
decorates_assigned :post

def show
Expand Down
3 changes: 3 additions & 0 deletions spec/dummy/config/initializers/draper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Draper.configure do |config|
config.default_controller = BaseController
end
4 changes: 2 additions & 2 deletions spec/dummy/spec/decorators/post_decorator_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
expect(xml).to have_css "post > updated-at", text: "overridden"
end

it "uses a test view context from ApplicationController" do
expect(Draper::ViewContext.current.controller).to be_an ApplicationController
it "uses a test view context from BaseController" do
expect(Draper::ViewContext.current.controller).to be_an BaseController
end
end
3 changes: 3 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ class ProductDecorator < Draper::Decorator; end
class OtherDecorator < Draper::Decorator; end
end

ApplicationController = Class.new(ActionController::Base)
CustomController = Class.new(ActionController::Base)

# After each example, revert changes made to the class
def protect_class(klass)
before { stub_const klass.name, Class.new(klass) }
Expand Down

0 comments on commit ff36bd8

Please sign in to comment.