Reputation: 128317
I'd like to be able to define a callback in DataMapper and have this happen in a transaction along with the accompanying update. For example:
class Comment
include DataMapper::Resource
has n, :updates
property :id, Serial
property :text, String
after :update do
self.updates.create(:text => self.text)
end
end
I think it's clear what the above code is trying to do: any time a Comment
is updated, also create a corresponding Update
record. Now, a possible scenario is that you could update a post, creating the update would fail—for whatever reason—and thus some history would be lost. So I would really like for this kind of operation to happen within a transaction.
Is this possible? I can think of some workarounds (e.g., defining a custom update
method); but I'm curious to know if there's a "correct" way or if others can think of elegant approaches.
Upvotes: 1
Views: 296
Reputation: 1042
To archive the same with an testable and extendable design I suggest a service object like this:
class CommentUpdate
private_class_method :new
# Run comment update within transaction
def self.run(*args)
Comment.transaction do
new(*args)
end
end
# Initialize object
#
# @param [Comment]
# the comment to update
# @param [String]
# the text to set
#
def initialize(comment, text)
@comment, @text = comment, text
run
end
# Test if update was successful
def successful?
@comment.saved?
end
private
# Run update
def run
@comment.text = @text
if @comment.save
@comment.updates.create(:text => @text)
end
end
end
# usage
comment = Comment.first
update = CommentUpdate.run(comment, "Some new cool text")
update.successful? # Use this to steer your control flow...
Upvotes: 7