-
-
Save bcooksey/5807278 to your computer and use it in GitHub Desktop.
This is the orignal, see the new one
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Hook < ActiveRecord::Base | |
attr_accessible :event, :account_id, :subscription_url, :target_url | |
validates_presence_of :event, :account_id, :subscription_url, :target_url | |
# Looks for an appropriate REST hook that matches the record, and triggers the hook if one exists. | |
def self.trigger(event, record) | |
hooks = Hook.find(:all, :conditions => { | |
:event => event, | |
:account_id => record.account_id, | |
}) | |
return if hooks.empty? | |
unless Rails.env.development? | |
hook = hooks.first | |
Rails.logger.info "Triggering REST hook: #{hook.inspect}" | |
RestClient.post(hook.target_url, record.to_json) do |response, request, result| | |
if response.code.eql? 410 | |
Rails.logger.info "Destroying REST hook because of 410 response: #{hook.inspect}" | |
hook.destroy | |
end | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'test_helper' | |
require 'fakeweb' | |
class HookTest < ActiveSupport::TestCase | |
def setup | |
@account = Factory(:account) | |
@subscription_url = "https://zapier.com/hooks/standard/wpGRPPcRxZt2GxBbSSeUAlWPBnhLiRWB/" | |
@target_url = "https://zapier.com/hooks/standard/wpGRPPcRxZt2GxBbSSeUAlWPBnhLiRWB/" | |
hook = Hook.create( | |
{ | |
"event" => "new_contact", | |
"account_id" => @account.id, | |
"subscription_url" => @subscription_url, | |
"target_url" => @target_url | |
} | |
) | |
@contact = Factory(:contact, :account => @account, | |
:first => 'Ryan', :last => 'Porter', :email => '[email protected]') | |
end | |
def test_trigger | |
FakeWeb.register_uri( | |
:post, | |
@target_url, | |
:body => 'irrelevant', | |
:status => ['200', 'Triggered'] | |
) | |
Hook.trigger('new_contact', @contact) | |
assert_equal "POST", FakeWeb.last_request.method | |
assert_equal @contact.to_json, FakeWeb.last_request.body | |
end | |
def test_trigger_remove_hook_on_410_response | |
FakeWeb.register_uri( | |
:post, | |
@target_url, | |
:body => 'irrelevant', | |
:status => ['410', 'Danger, Will Robinson!'] | |
) | |
Hook.trigger('new_contact', @contact) | |
assert_equal "POST", FakeWeb.last_request.method | |
assert_equal @contact.to_json, FakeWeb.last_request.body | |
assert_equal 0, Hook.count # The 410 response should trigger removal of the hook. | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class HooksController < ApplicationController | |
def create | |
hook = Hook.new params | |
render :nothing => true, :status => 500 and return unless hook.save | |
Rails.logger.info "Created REST hook: #{hook.inspect}" | |
# The Zapier documentation says to return 201 - Created. | |
render :json => hook.to_json(:only => :id), :status => 201 | |
end | |
def destroy | |
hook = Hook.find(params[:id]) if params[:id] | |
if hook.nil? && params[:subscription_url] | |
hook = Hook.find_by_subscription_url(params[:subscription_url]).destroy | |
end | |
Rails.logger.info "Destroying REST hook: #{hook.inspect}" | |
hook.destroy | |
render :nothing => true, :status => 200 | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'test_helper' | |
class HooksControllerTest < ActionController::TestCase | |
def setup | |
@account = Factory(:account) | |
@user = Factory(:user, :username => 'username') # Password: "password", by default. | |
@staff = Factory(:staff, :account => @account, :user => @user) | |
end | |
def test_subscribe_requires_authentication | |
post :create, | |
{ | |
"event" => "new_contact", | |
"subscription_url" => "whatever", | |
"target_url" => "whatever" | |
} | |
assert_redirected_to :controller => 'public/signin', :action => 'signin' | |
end | |
def test_subscribe | |
@request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64::encode64("username:password") | |
subscription_url = "https://zapier.com/hooks/standard/wpGRPPcRxZt2GxBbSSeUAlWPBnhLiRWB/" | |
target_url = "https://zapier.com/hooks/standard/wpGRPPcRxZt2GxBbSSeUAlWPBnhLiRWB/" | |
post :create, | |
{ | |
"event" => "new_contact", | |
"account_id" => @account.id, | |
"subscription_url" => subscription_url, | |
"target_url" => target_url | |
} | |
assert_response 201 | |
assert_equal 1, Hook.count | |
hook = Hook.last | |
assert_equal %Q[{"id":#{hook.id}}], @response.body | |
assert_equal "new_contact", hook.event | |
assert_equal @account.id, hook.account_id.to_i | |
assert_equal subscription_url, hook.subscription_url | |
assert_equal target_url, hook.target_url | |
end | |
def test_subscribe_error | |
@request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64::encode64("username:password") | |
post :create, nil | |
assert_response 500 | |
assert_equal 0, Hook.count | |
end | |
def test_unsubscribe_rest | |
@request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64::encode64("username:password") | |
hook = Hook.create( | |
:event => "new_contact", | |
:account_id => @account.id, | |
:subscription_url => 'whatever', | |
:target_url => 'whatever' | |
) | |
assert_equal 1, Hook.count | |
post :destroy, | |
{ | |
:id => hook.id.to_s, | |
:subscription_url => 'whatever' | |
} | |
assert_response 200 | |
assert_equal 0, Hook.count | |
end | |
def test_unsubscribe_the_hacky_way | |
@request.env["HTTP_AUTHORIZATION"] = "Basic " + Base64::encode64("username:password") | |
subscription_url = "https://zapier.com/hooks/standard/wpGRPPcRxZt2GxBbSSeUAlWPBnhLiRWB/" | |
target_url = "https://zapier.com/hooks/standard/wpGRPPcRxZt2GxBbSSeUAlWPBnhLiRWB/" | |
Hook.create( | |
:event => "new_contact", | |
:account_id => @account.id, | |
:subscription_url => subscription_url, | |
:target_url => target_url | |
) | |
assert_equal 1, Hook.count | |
post :destroy, | |
{ | |
"subscription_url" => subscription_url | |
} | |
assert_response 200 | |
assert_equal 0, Hook.count | |
end | |
end |
Updated the main fork again to check for an applicable hook before enqueuing a Resque job.
And to run ALL applicable hooks (instead of just the first match).
And to demonstrate using Resque-Retry for dealing with Resque worker jobs that run before the transaction is closed. If you're using Rails 3 then use "after_commit :do_something, :on => :create" instead.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
FYI: I updated the original fork just now to support triggering REST hooks from Resque background jobs.