Skip to content

Commit

Permalink
Merge 7240ae3 into d35bed3
Browse files Browse the repository at this point in the history
  • Loading branch information
kookster committed Jun 4, 2015
2 parents d35bed3 + 7240ae3 commit 5130b32
Show file tree
Hide file tree
Showing 27 changed files with 334 additions and 28 deletions.
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ gem 'oj_mimic_json'

## Messaging
gem 'shoryuken'
gem 'announce'

## Deployment
# configuration
Expand Down
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ GEM
tzinfo (~> 1.1)
acts_as_list (0.7.0)
activerecord (>= 3.0)
announce (0.2.2)
ansi (1.5.0)
arel (6.0.0)
aws-sdk-core (2.0.41)
Expand Down Expand Up @@ -393,6 +394,7 @@ PLATFORMS
DEPENDENCIES
actionpack-action_caching
acts_as_list
announce
better_errors
binding_of_caller
capistrano (~> 3.2)
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/base_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class Api::BaseController < ApplicationController

include ApiVersioning
include HalActions
include AnnounceActions
include Roar::Rails::ControllerAdditions

# respond to hal or json, but always returns application/hal+json
Expand All @@ -17,7 +18,6 @@ class Api::BaseController < ApplicationController
allow_params :index, [:page, :per, :zoom]

cache_api_action :show

cache_api_action :index

caches_action :entrypoint, cache_path: ->(_c) { { _c: Api.version(api_version).cache_key } }
Expand Down
12 changes: 12 additions & 0 deletions app/controllers/api/stories_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ class Api::StoriesController < Api::BaseController

filter_resources_by :series_id, :account_id

announce_actions :create, :update, :delete, :publish, :unpublish

def publish
resource.publish!
show
end

def unpublish
resource.unpublish!
show
end

def random
@story = Story.published.limit(1).order('RAND()').first
show
Expand Down
48 changes: 48 additions & 0 deletions app/controllers/concerns/announce_actions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# encoding: utf-8

require 'active_support/concern'
require 'announce_actions/announce_filter'

# expects underlying model to have filename, class, and id attributes
module AnnounceActions
extend ActiveSupport::Concern

module ClassMethods
attr_accessor :announced_actions

def announce_actions(*args)
self.announced_actions ||= []

options = args.extract_options!

actions = args.map(&:to_s).uniq
actions = [:create, :update, :destroy] if actions.empty?

actions.each do |action|
next if announced_actions.include?(action)

add_announce_filter(action, options)

# remember this action already announcing, prevent dupes
self.announced_actions << action
end
end

def add_announce_filter(action, options)
# when it is a destroy action, default action name to 'delete'
announce_filter = new_announce_filter(action, options)

# default callback options for only this action, and only on success
default_options = { only: [action], if: ->() { response.successful? } }
callback_options = options.slice(:only, :except, :if, :unless)

after_action announce_filter, default_options.merge(callback_options)
end

def new_announce_filter(action, options)
filter_options = options.slice(:action, :decorator)
filter_options[:action] ||= 'delete' if action.to_s == 'destroy'
AnnounceActions::AnnounceFilter.new(action, filter_options)
end
end
end
46 changes: 46 additions & 0 deletions app/controllers/concerns/announce_actions/announce_filter.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# encoding: utf-8

require 'announce'

# expects underlying model to have filename, class, and id attributes
module AnnounceActions

class AnnounceFilter
include Announce::Publisher

attr_accessor :action, :options

def initialize(action, options = {})
@action = action
@options = options
end

def after(controller)
subject = controller.controller_name.singularize
announce(subject, resource_action, decorated_resource(controller))
end

def resource_action
(options[:action] || action).to_s
end

def decorated_resource(controller)
decorator = decorator_class(controller)
raise "No decorator specified: #{controller.inspect}" unless decorator
res = announce_resource(action, controller)
decorator.new(res).to_json
end

def announce_resource(action, controller)
pre = "#{action}_" if controller.respond_to?("#{action}_resource", true)
controller.send("#{pre}resource")
end

def decorator_class(controller)
return options[:decorator] if options[:decorator]
resource_class = controller.controller_name.singularize.camelize
"Api::Min::#{resource_class}Representer".safe_constantize ||
"Api::#{resource_class}Representer".safe_constantize
end
end
end
2 changes: 0 additions & 2 deletions app/controllers/concerns/api_versioning.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,5 @@ def api_versions(*versions)
self.understood_api_versions = versions.map(&:to_s)
before_filter :check_api_version
end

end

end
1 change: 0 additions & 1 deletion app/controllers/public_assets_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,4 @@ def show
head 401
end
end

end
18 changes: 18 additions & 0 deletions app/models/story.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,24 @@ def subscription_episode?
series && series.subscribable?
end

# raising exceptions here to prevent sending publish messages
# when not actually a change to be published
def publish!
if published_at
raise "Story #{id} is already published."
else
update_attributes!(published_at: Time.now)
end
end

def unpublish!
if !published_at
raise "Story #{id} is not published."
else
update_attributes!(published_at: nil)
end
end

def destroy
if v4?
really_destroy!
Expand Down
1 change: 0 additions & 1 deletion app/representers/concerns/caches.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,4 @@ def cache_key_class_name
def cache_options
{compress: true, race_condition_ttl: 10, expires_in: 1.hour}
end

end
2 changes: 0 additions & 2 deletions app/representers/concerns/curies.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,5 @@ def collection(name, options={})
options[:as] = curify(options[:as] || name) if options[:embedded]
super(name, options)
end

end

end
3 changes: 0 additions & 3 deletions app/representers/concerns/embeds.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ def embed_zoomed?(name, zoom_def=nil, zoom_param=nil)
# then do not zoom when this name is not in the request
zoom_param.nil? ? zoom_def : zoom_param.include?(name)
end

end

# Possible values for zoom option in the embed representer definition
Expand Down Expand Up @@ -86,7 +85,5 @@ def embeds(name, options={})

collection(name, options)
end

end

end
2 changes: 0 additions & 2 deletions app/representers/concerns/format_keys.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,5 @@ def collection(name, options={})
options[:as] = options[:embedded] ? n.dasherize : n.camelize(:lower)
super(name, options)
end

end

end
10 changes: 10 additions & 0 deletions config/announce.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Configuration file that defines the settings for pub/sub of events
app_name: cms

publish:
story:
- create
- update
- delete
- publish
- unpublish
2 changes: 2 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ class Application < Rails::Application
end

config.active_job.queue_adapter = :shoryuken
config.active_job.queue_name_prefix = Rails.env
config.active_job.queue_name_delimiter = '_'

config.active_record.raise_in_transactional_callbacks = true
end
Expand Down
1 change: 1 addition & 0 deletions config/initializers/announce.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Announce::configure
3 changes: 3 additions & 0 deletions config/initializers/shoryuken.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
require 'shoryuken'

Shoryuken::EnvironmentLoader.load(config_file: (Rails.root + 'config' + 'shoryuken.yml'))
7 changes: 7 additions & 0 deletions config/shoryuken.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
aws:
access_key_id: <%= ENV['AWS_ACCESS_KEY_ID'] %>
secret_access_key: <%= ENV['AWS_SECRET_ACCESS_KEY'] %>
region: <%= ENV['AWS_REGION'] %>
account_id: <%= ENV['AWS_ACCOUNT_ID'] %>
concurrency: 25 # The number of allocated threads to process messages. Default 25
delay: 30 # The delay in seconds to pause a queue when it's empty. Default 0
48 changes: 48 additions & 0 deletions test/controllers/concerns/announce_actions/announce_filter_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# encoding: utf-8

require 'announce_actions'

describe AnnounceActions::AnnounceFilter do

let(:controller_class) { Api::TestObjectsController }

let(:controller) { controller_class.new }

let(:filter) { AnnounceActions::AnnounceFilter.new('create', {}) }

before do
controller_class.class_eval do
include AnnounceActions
announce_actions
end

clear_messages
end

it 'is created with an action and a options' do
filter.action.must_equal('create')
filter.options.must_equal({})
end

it 'defaults to the min decorator when possible' do
dc = filter.decorator_class(controller)
dc.must_equal Api::Min::TestObjectRepresenter
end

it 'can use an optional decorator' do
filter.options[:decorator] = Api::TestObjectRepresenter
dc = filter.decorator_class(controller)
dc.must_equal Api::TestObjectRepresenter
end

it 'can use an optional action name' do
filter.resource_action.must_equal('create')
filter.options[:action] = 'foo'
filter.resource_action.must_equal('foo')
end

it 'tries the action specific resource method' do
def controller.foo_resource; 'foo'; end
filter.announce_resource('foo', controller).must_equal 'foo'
end
end
57 changes: 57 additions & 0 deletions test/controllers/concerns/announce_actions_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# encoding: utf-8

require 'announce_actions'

describe Api::TestObjectsController do

let (:controller_class) { Api::TestObjectsController }

before do
controller_class.class_eval { include AnnounceActions }
controller_class.announced_actions = []
clear_messages
end

it 'can declare announced actions' do
controller_class.announce_actions(:destroy)
controller_class.announced_actions.size.must_equal 1
end

it 'prevents dupe announcements' do
controller_class.announce_actions(:destroy)
controller_class.announce_actions(:destroy, :update)
controller_class.announced_actions.size.must_equal 2
end

it 'defaults to create, update, and destroy' do
default_actions = [:create, :destroy, :update]
controller_class.announce_actions
controller_class.announced_actions.sort.must_equal default_actions
end

describe 'test callbacks' do

before { define_routes }
after { Rails.application.reload_routes! }

it 'will call announce' do
controller_class.announce_actions(:create)

post :create, { title: 'foo' }.to_json

response.must_be :success?
last_message['subject'].to_s.must_equal 'test_object'
last_message['action'].to_s.must_equal 'create'
end

it 'renames destroy action to delete' do
controller_class.announce_actions(:destroy)

delete :destroy, id: 1

response.must_be :success?
last_message['subject'].to_s.must_equal 'test_object'
last_message['action'].to_s.must_equal 'delete'
end
end
end
7 changes: 4 additions & 3 deletions test/controllers/concerns/api_versioning_test.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# encoding: utf-8

describe ApiVersioning do

class ApiVersioningTestController < ActionController::Base
include ApiVersioning
include ApiVersioning
end

let (:controller) { ApiVersioningTestController.new }
Expand All @@ -10,5 +12,4 @@ class ApiVersioningTestController < ActionController::Base
ApiVersioningTestController.api_versions(:v0)
ApiVersioningTestController.understood_api_versions.must_equal ['v0']
end

end
end
2 changes: 2 additions & 0 deletions test/controllers/concerns/hal_actions_test.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# encoding: utf-8

require 'hal_actions'

describe HalActions do
Expand Down
Loading

0 comments on commit 5130b32

Please sign in to comment.