Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Web Hook Generator #34

Merged
merged 4 commits into from
Nov 25, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 23 additions & 2 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ FYI, {Mandrill}[http://mandrill.com/] is the transactional email service by the
* Requires Rails >= 3.0.3 (including 3.1, 3.2 and 4).

Food for thought (upcoming features maybe)..
* some generators may be handy to avoid the manual coding to wire up web hooks
* I thought about implementing this as an engine, but the overhead did not seem appropriate. Maybe that view will change..

== The Mandrill::Rails Cookbook
Expand Down Expand Up @@ -48,7 +47,29 @@ See the section below on 'Contributing to Mandrill::Rails' for more information.

Say we have configured Mandrill to send requests to /inbox at our site (see the next recipes for how you do that).

Once we have Mandrill::Rails in our project, we just need to do two things. There's no generator to help you do this at the moment, but it is pretty simple:
Once we have Mandrill::Rails in our project, we just need to do two things. You can run a generator to do it for you, or you can configure things manually:

==== Using the generator

Run the generator and specify the name for your route and controller:

rails generate mandrill inbox

This will create a resource route and corresponding controller at /inbox.

If you need a namespaced controller, specify it in the name:

rails generate mandrill hooks/inbox

This creates an `inbox` route that points to the `Hooks:InboxController` class.

If you prefer pluralized names, that can be specified with a flag:

rails generate mandrill inbox --pluralize_names

This will create an `InboxesController` class and a resource route called `inboxes`.

==== Manual configuration

First, configure a resource route:

Expand Down
18 changes: 18 additions & 0 deletions lib/generators/templates/controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
class <%= @controller_name %>Controller < ApplicationController
include Mandrill::Rails::WebHookProcessor

# To completely ignore unhandled events (not even logging), uncomment this line
# ignore_unhandled_events!

# If you want unhandled events to raise a hard exception, uncomment this line
# unhandled_events_raise_exceptions!

# To enable authentication, uncomment this line and set your API key.
# It is recommended you pull your API keys from environment settings,
# or use some other means to avoid committing the API keys in your source code.
# authenticate_with_mandrill_keys! 'YOUR_MANDRILL_WEBHOOK_KEY'

def handle_inbound(event_payload)
head(:ok)
end
end
83 changes: 83 additions & 0 deletions lib/generators/web_hook_generator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
require 'rails/generators/named_base'

module Mandrill
module Rails
module Generators
class WebHookGenerator < ::Rails::Generators::Base
namespace 'mandrill'
desc 'Generates a controller and routes for Mandrill web hooks.'
argument :name, type: :string
class_option :pluralize_names, aliases: '-p', type: :boolean, default: false,
desc: 'Pluralize names in route and controller'
class_option :routes, type: :boolean, default: true,
desc: 'Creates routes for web hooks'
class_option :controller, type: :boolean, default: true,
desc: 'Creates a controller for web hooks'

source_root File.expand_path("../templates", __FILE__)

def initialize(args, *options)
args[0] = args[0].dup if args[0].is_a?(String) && args[0].frozen?
super
assign_names!(self.name)
end

def add_routes
return unless options.routes?
hook_route = "resource :#{resource_name}"

controller = controller_path

hook_route << %Q(, :controller => '#{controller}')
hook_route << %Q(, :only => [:show,:create])
route hook_route
end

def add_controller
return unless options.controller?
@controller_name = class_name
template 'controller.rb', controller_destination
end

private

attr_reader :file_name

def assign_names!(name)
@class_path = name.include?('/') ? name.split('/') : name.split('::')
@class_path.map!(&:underscore)
@file_name = @class_path.pop
end

def class_name
@class_name ||= (@class_path + [resource_name]).map!(&:camelize).join('::')
end

def controller_destination
"app/controllers/#{controller_path}_controller.rb"
end

def controller_path
@controller_path ||= if class_name.include?('::')
@class_path.collect {|dname| dname }.join + "/" + resource_name
else
resource_name
end
end

def plural_name
@plural_name ||= singular_name.pluralize
end

def resource_name
return singular_name unless options.pluralize_names?
plural_name
end

def singular_name
file_name.downcase
end
end
end
end
end
1 change: 1 addition & 0 deletions mandrill-rails.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
spec.add_development_dependency "bundler", "~> 1.7"
spec.add_development_dependency "rake", "~> 10.0"
spec.add_development_dependency "rspec", "~> 3.0"
spec.add_development_dependency "generator_spec", "~> 0.9"
spec.add_development_dependency "guard-rspec", "~> 4.5"
spec.add_development_dependency "rdoc"

Expand Down
246 changes: 246 additions & 0 deletions spec/generators/web_hook_generator_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
require 'spec_helper'
require 'generator_spec'
require 'generators/web_hook_generator'

describe Mandrill::Rails::Generators::WebHookGenerator, type: :generator do
destination File.expand_path("../../tmp", __FILE__)

before do
prepare_destination
copy_routes
end

describe 'route generation' do
context 'with no pluralized option' do
context 'with simple names' do
before { run_generator %w(inbox) }

it 'creates a proper route' do
match = "resource :inbox, :controller => 'inbox', :only => [:show,:create]"
expect(destination_root).to have_structure {
directory 'config' do
file 'routes.rb' do
contains match
end
end
}
end
end

context 'with namespaced names' do
before { run_generator %w(hooks/inbox) }

it 'creates a proper route' do
match = "resource :inbox, :controller => 'hooks/inbox', :only => [:show,:create]"
expect(destination_root).to have_structure {
directory 'config' do
file 'routes.rb' do
contains match
end
end
}
end
end

context 'with capitalized names' do
before { run_generator %w(Inbox) }

it 'creates a proper route' do
match = "resource :inbox, :controller => 'inbox', :only => [:show,:create]"
expect(destination_root).to have_structure {
directory 'config' do
file 'routes.rb' do
contains match
end
end
}
end
end
end

context 'with an explicit pluralized option' do
context 'with simple names' do
before { run_generator %w(inbox --pluralize_names) }

it 'creates a proper route' do
match = "resource :inboxes, :controller => 'inboxes', :only => [:show,:create]"
expect(destination_root).to have_structure {
directory 'config' do
file 'routes.rb' do
contains match
end
end
}
end
end

context 'with namespaced names' do
before { run_generator %w(hooks/inbox --pluralize_names) }

it 'creates a proper route' do
match = "resource :inboxes, :controller => 'hooks/inboxes', :only => [:show,:create]"
expect(destination_root).to have_structure {
directory 'config' do
file 'routes.rb' do
contains match
end
end
}
end
end

context 'with capitalized names' do
before { run_generator %w(hooks/Inbox --pluralize_names) }

it 'creates a proper route' do
match = "resource :inboxes, :controller => 'hooks/inboxes', :only => [:show,:create]"
expect(destination_root).to have_structure {
directory 'config' do
file 'routes.rb' do
contains match
end
end
}
end
end
end
end

describe 'controller generation' do
context 'with controller explicitly skipped' do
before { run_generator %w(inbox --skip-controller) }

it 'does not create a controller file' do
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
no_file 'inbox_controller.rb'
end
end
}
end
end

context 'with no pluralized option' do
context 'with simple names' do
before { run_generator %w(inbox) }

it 'creates a proper controller file' do
match = 'class InboxController < ApplicationController'
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
file 'inbox_controller.rb' do
contains match
end
end
end
}
end
end

context 'with namespaced names' do
before { run_generator %w(hooks/inbox) }

it 'creates a proper controller file' do
match = 'class Hooks::InboxController < ApplicationController'
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
directory 'hooks' do
file 'inbox_controller.rb' do
contains match
end
end
end
end
}
end
end

context 'with capitalized names' do
before { run_generator %w(hooks/Inbox) }

it 'creates a proper controller file' do
match = 'class Hooks::InboxController < ApplicationController'
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
directory 'hooks' do
file 'inbox_controller.rb' do
contains match
end
end
end
end
}
end
end
end

context 'with an explicit pluralized option' do
context 'with simple names' do
before { run_generator %w(inbox --pluralize_names) }

it 'creates a proper controller file' do
match = 'class InboxesController < ApplicationController'
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
file 'inboxes_controller.rb' do
contains match
end
end
end
}
end
end

context 'with namespaced names' do
before { run_generator %w(hooks/inbox --pluralize_names) }

it 'creates a proper controller file' do
match = 'class Hooks::InboxesController < ApplicationController'
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
directory 'hooks' do
file 'inboxes_controller.rb' do
contains match
end
end
end
end
}
end
end

context 'with capitalized names' do
before { run_generator %w(hooks/Inboxes --pluralized_names) }

it 'creates a proper controller file' do
match = 'class Hooks::InboxesController < ApplicationController'
expect(destination_root).to have_structure {
directory 'app' do
directory 'controllers' do
directory 'hooks' do
file 'inboxes_controller.rb' do
contains match
end
end
end
end
}
end
end
end
end
end

def copy_routes
routes = File.expand_path('../../rails_app/config/routes.rb', __FILE__)
destination = File.join(destination_root, 'config')

FileUtils.mkdir_p(destination)
FileUtils.cp routes, destination
end
Loading