Last active
December 14, 2015 05:09
-
-
Save bdmac/5032984 to your computer and use it in GitHub Desktop.
Proposal to modify rails-core with optimistic locking enhancements or turn this into a gem.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Automatically adds lock_version to model forms if the underlying | |
# model has locking_enabled. | |
module ActionView | |
module Helpers | |
module OptimisticLockingFormFor | |
def self.included(base) | |
base.alias_method_chain :form_for, :optimistic_locking | |
base.alias_method_chain :fields_for, :optimistic_locking | |
end | |
def form_for_with_optimistic_locking(record_or_name_or_array, *args, &block) | |
form_for_without_optimistic_locking(record_or_name_or_array, *args) do |form_with_locking| | |
build_lockable_form(form_with_locking, &block) | |
end | |
end | |
def fields_for_with_optimistic_locking(record_name, record_object = nil, options = {}, &block) | |
fields_for_with_optimistic_locking(record_name, record_object, options) do |fiels_for_with_locking| | |
build_lockable_form(fields_for_with_locking, &block) | |
end | |
end | |
private | |
def build_lockable_form(builder, &block) | |
lock_form = builder.object && | |
builder.object.respond_to?(:locking_enabled?) && | |
builder.object.locking_enabled? && | |
!builder.object.new_record? | |
concat(content_tag(:div, | |
builder.hidden_field(builder.object.class.locking_column), | |
:style => 'margin:0;padding:0;display:inline').html_safe) if lock_form | |
yield builder | |
end | |
end | |
end | |
end | |
ActionView::Base.send :include, ActionView::Helpers::OptimisticLockingFormFor | |
# Automatically add data-params for the model's lock_version | |
# when lock_with: is specified in link_to. | |
# Usage: link_to(name, url_for(model), remote: true, method: :put, lock_with: model) | |
module ActionView | |
module Helpers | |
module LockVersionUrlHelper | |
def self.included(base) | |
base.alias_method_chain :convert_options_to_data_attributes, :optimistic_locking | |
end | |
private | |
def convert_options_to_data_attributes_with_optimistic_locking(options, html_options) | |
the_options = convert_options_to_data_attributes_without_optimistic_locking(options, html_options) | |
if the_options && the_options['lock_with'] && the_options['lock_with'].kind_of?(ActiveRecord::Base) | |
model_object = the_options.delete('lock_with') | |
if model_object.respond_to?(:locking_enabled?) && model_object.locking_enabled? && !model_object.new_record? | |
locking_column = model_object.class.locking_column | |
lock_version = model_object.send(locking_column.to_sym) | |
if the_options['data-params'].present? | |
the_options['data-params'] += "&#{locking_column}=#{lock_version}" | |
else | |
the_options['data-params'] = "#{locking_column}=#{lock_version}" | |
end | |
end | |
end | |
the_options | |
end | |
end | |
end | |
end | |
ActionView::Base.send :include, ActionView::Helpers::LockVersionUrlHelper | |
# Automatically permit lock_version whenever #permit is called on params. | |
# Note that this assumes the locking column is named lock_version which | |
# may not be true if overridden in the model class. Unfortunately there's | |
# no way I can see to determine the appropriate locking column to use from | |
# here with no access to the model in use. | |
# | |
# I'm least happy with this proposal... | |
module ActionController | |
module LockVersionParameters | |
def self.included(base) | |
base.alias_method_chain :permit, :optimistic_locking | |
end | |
def permit_with_optimistic_locking(*filters) | |
filters << 'lock_version' | |
permit_without_optimistic_locking(filters) | |
end | |
end | |
end | |
ActionController::Parameters.send :include, ActionController::LockVersionParameters |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment