3 ms·
Maybe it's because I've been reading about DCI lately, but I think this example could go even further in moving business logic out of the AR model. class G
by swanson 14y ago
Maybe it's because I've been reading about DCI lately, but I think this example could go even further in moving business logic out of the AR model.
class GuestbookLibrarian
def initialize(rate_limiter, tweeter, spam_checker)
@rate_limiter = rate_limiter
@tweeter = tweeter
@spam_checker = spam_checker
end
def add_entry(name, msg, ip_addr)
raise PostingTooSpammy if @spam_checker.is_spammy? msg
raise PostingTooFast if @rate_limiter.exceeded? ip_addr
entry = GuestbookEntry.create(:name => name,
:msg => msg,
:ip_addr => ip_addr)
@rate_limiter.record(ip_addr)
@tweeter.tweet_new_guestbook_post(name, msg)
entry
end
end
class GuestbookController < ApplicationController
... SNIP ...
rescue_from PostingTooSpammy, :with => :some_spam_handler
rescue_from PostingTooFast, :with => :some_other_spam_handler
def create
#maybe these should be globals in an initializer somewhere if we
#use them elsewhere? or in a :before_filter at least :)
rate_limiter = UserContentRateLimiter.new
tweeter = Tweeter.new
spam_checker = UserContentSpamChecker.new
librarian = GuestbookLibrarian.new(rate_limiter, tweeter, spam_checker)
entry = librarian.add_entry(params[:name], params[:msg], params[:ip_addr])
redirect_to entry, :notice => "Thanks for posting"
end
end
Something like that? Too Java-y? Feedback appreciated :)
- r00k 14y agoInteresting approach. It'd be a bit surprising in a Rails app, however, since models usually handle their own validation. That said, the fact that GuestBookEntry doesn't have validation as a concern does make it simpler. I might refactor to something like this if a particular model had extremely complicated validation logic, but wouldn't ever do this as a first pass.
- swanson 14y agoI think in general models can handle their own validation (especially if you use AR), but I guess the difference is that these validations hit external "services", instead of like a :max_length validation. I agree on the first pass comment - I imagine that the user stories went something like: * v1 - An anon user can post to the guestbook * v2 - Guestbook comments are checked for spam * v3 - Post guestbook comments to twitter for Web 2.0-ness And this is the refactored version after v3
- vidarh 14y agoNot too Java-y, but too "DataMapper-y" for most Rails devs, I think (the pattern, not the ORM - the Ruby DataMapper ORM implements the ActiveRecord pattern, though DataMapper 2 actually finally will implement DataMapper) EDIT: This is an interesting overview of where DataMapper 2 is going as a parallel to your example: http://solnic.eu/2012/01/10/ruby-datamapper-status.html http://solnic.eu/2012/01/10/ruby-datamapper-status.html