conflict_warnings is an ActionController extension that provides methods of preventing data inconsistencies that could arise from multiple users interacting with the same resource at roughly the same time. Essentially providing Optimistic Locking persisting across requests. Named after the HTTP 409 Conflict status, conflict_warnings determines if a database conflict is likely and intercepts potentailly dangerous requests.
From the root of your rails project run the following command:
./script/plugin install git://github.com/EmFi/conflict_warnings.git
Add either filter_conflicts, filter_stale_optimistic_locks or filter_resource_conflicts to your controllers as if they were a before filter.
class ExamplesController < ApplicationController filter_conflicts end
class LockExampleController < ApplicationController filter_stale_optimistic_locks end class ExamplesController < ApplicationController filter_resources_conflicts :only => :update end
Controller Instance Methods
The underlying methods are also provided for use in your own filters, as catch_conflict, catch_stale_optimistic_locks and catch_resource_conflict.
class LockingResourcesController < ApplicationController before_filter :login_required, :acquire_lock protected def acquire_lock catch_resources_unavailable current_user, :accessor => :acquire_lock_for_user end end end
The ConflictWarnings methods will use the options supplied and the params to select a model in the database and apply an accessor to identify problem requests.
By default the model associated with the controller handling the request is used, will be used to find the instance with an id of params[:id].
filter_conflicts and catch_conflicts compare a timestamp passed in the link against the updated_at column of the instance. Helpers are provided for creating links with this timestamp. If the model was modified after the timestamp, the request interrupted.
filter_stale_optimistic_locks and catch_stale_optimistic_locks compare a lock version passed in the link against the lock_version fo the the selected instance.
filter_resources_unavialable and catch_conflicts will check for an instance method that ends with available. If this method returns 0 or a false value, the request is interrupted.
Without any options interrupted requests redirect to the referring request, essentially reloading the page and any changes.
conflict_warnings provides view helpers that add parameters catch_conflicts require to links:
<%= link_to_remote_with_timestamp("Confirm", confirm_event_url(@event) %>
<%= f.timestamp %>
<%= timestamp_tag %>
page.call('replaceTimeStamps', params[:page_rendered_at], Time.now.to_i)
This plugin comes with generated documentation for its provided methods and classes in the doc folder.
In depth documentation of filter_conflicts, filter_stale_optimistic_locks and filter_resources_unavailable can be found in ConflictWarnings::ActionController::ClassMethods#. While documentation of catch_conflicts, catch_stale_optimistic_locks and catch_resources_unavaialble can be found in ConflictWarnigns::ActionController::InstanceMethods#.
conflict_warnings provides view helpers that add parameters catch_conflicts require to links. They can be found in ConflictWarnings::ActionView::Helpers::UrlHelper, ConflictWarnings::ActionView::Helpers::PrototypeHelper, ConflictWarnings::ActionView::Helpers::FormHelper, and ConflictWarnings::ActionView::Helpers::FormTagHelper
If catch_conflicts, catch_stale_optimistic_locks, catch_resource_conflict, filter_conflicts, filter_stale_optimistic_locks and filter_resource_conflicts, not receive enough information to reach a decision it will usually assumes the action is harmful. Records that produce a nil value for comparing a time or lock version against a counterpart value(provided in the paremters) will be allowed to complete successfully.
At present forms are not handled well. With the default options, a users' form will be overwritten by the changes to the record that occured between page load and submit. You will have to provide a template to caputre the form from the params hash and figure out a way to display the merged data.
Things To Do:
* Handle additional formats beyond html and js * Write form builder to allow for automatic side by side comparison of conflicting form data.
Copyright © 2009 Emery Finkelstein, released under the MIT license