-
-
Save skwp/5302250 to your computer and use it in GitHub Desktop.
class Reverb::Actions::WatchListing | |
def self.watch(user, product, listener) | |
if product.owner?(user) | |
listener.failure(I18n.t('flash.watchlist.error_own')) | |
else | |
Reverb::Analytics.track(user, :watch_product) # FIXME, this doesn't belong here | |
user.user_watch_products.create(:product_id => product.id) | |
listener.success | |
end | |
end | |
end |
module Reverb | |
class Wants < Grape::API | |
post '/wants' do | |
class WatchListingResponder < SimpleDelegator | |
def success | |
{"success" => true} | |
end | |
def failure(message) | |
error!({ "error" => message}, 412) | |
end | |
end | |
Reverb::Actions::WatchListing.watch(current_user, Product.find(params[:id]), WatchListingResponder.new(self)) | |
end | |
end | |
end |
class Dashboard::Buying::WatchedProductsController < Dashboard::BaseController | |
def create | |
product = Product.find(params[:id]) | |
Reverb::Actions::WatchListing.watch(current_user, product, WatchListingResponder.new(self)) | |
redirect_to product_url(product) | |
end | |
private | |
class WatchListingResponder < SimpleDelegator | |
def success | |
flash[:success] = "Listing has been added to #{link_to_watchlist}." | |
end | |
def failure(message) | |
flash[:error] = message | |
end | |
def link_to_watchlist | |
view_context.link_to 'your watchlist', dashboard_buying_watched_products_url | |
end | |
end | |
end |
describe Dashboard::Buying::WatchedProductsController do | |
stub_user | |
let(:product) { mock('product', :id => 1) } | |
before { Product.stub(:find).with("1") { product } } | |
describe "#create" do | |
let(:responder) { Dashboard::Buying::WatchedProductsController::WatchListingResponder.new(subject) } | |
it "watches the listing" do | |
Reverb::Actions::WatchListing.should_receive(:watch).with(user, product, anything) | |
post :create, :id => product.id | |
response.should redirect_to product_url(product) | |
end | |
it "handles error display" do | |
responder.failure("foo") | |
flash[:error].should == "foo" | |
end | |
it "handles success display" do | |
responder.success | |
flash[:success].should =~ /Listing has been added to.*your watchlist.*/ | |
end | |
end | |
end |
I'm not sure I fully got my head around your domain, but hopefully enough to offer you some useful insight.
It seems to me that Reverb::Analytics
should be another listener. So your listener API needs to change so that it sends out enough information that the analytics code could become another consumer of that API.
If you're worried about duplicating the wiring, then maybe the thing that does the wiring deserves it's own abstraction, so that you can reuse it.
Thank you for the comments, @mattwynne. Agreed, the analytics should be a listener. As far as abstracting the wiring, that's definitely an idea. I mean essentially what i'm going for is that Reverb::Analytics would eventually be wired into pretty much every business class.
I'm also looking toward the future and implementing activity streams. Maybe the listener api is that the business case sends out a success with a sort of actor/action/properties stream which can then be picked up by listeners such as analytics, activity stream processors, etc.
Again the biggest question is where the wiring happens. Your statement about abstracting the wiring makes sense to me in principle but..would it look something like this? A base class that sets up default listeners and children then add to that...
class AnalyticsListener
def success(actor, action, properties)
end
end
class ActivityStreamListener
def success(actor, action, properties)
end
end
class BaseAction
def initialize
@listeners << [AnalyticsListener.new, ActivityStreamListener.new]
end
end
class SomeBusinessCase < BaseAction
def initialize(params, listeners)
@listeners << listeners
end
end
SomeBusinessCase.new(params, my_actual_listener)
What about that approach: https://github.com/krisleech/wisper ?
I'd like to move the analytics logic out of the business use case, however there is no good place for it. This is maybe the case where something like AOP would win. I can put a wiring to an analytics service listener in the controller, but then I'd have to duplicate it in the api, the console, rake tasks, and any other place that would care to reuse the business logic.