Skip to content

Commit

Permalink
improve support for optimistic locking
Browse files Browse the repository at this point in the history
hidden field for locking column is added automatically in base_form for update action, and any other action which has add_locking_column setting, or if partial is rendered passing add_locking_column in locals.

on_stale_object_error is called in update action when StaleObjectError exception is rescued
  • Loading branch information
scambra committed Oct 25, 2024
1 parent 1b6dcb8 commit da0636a
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 5 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.rdoc
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
- Add css_class to action links, to avoid changing name, it may result confusing, deprecate name setter
- Add buttons to check all and uncheck all on :select form ui for collection associations, and draggable lists (active_scaffold_checkbox_list)
- Add css_class to action links, to avoid changing name, it may result confusing, deprecate name setter.
- Add buttons to check all and uncheck all on :select form ui for collection associations, and draggable lists (active_scaffold_checkbox_list).
- Add hidden field with locking column in base_form partial for persisted records automatically, if model uses optimistic locking.
- Add on_stale_object_error when StaleObjectError is rescued, to allow customization.

= 3.7.8
- Rollback previous behaviour when submitting empty values, broken when default_value was added. Default value set in column is not used when trying to save empty value, DB default is used in that case, and save NULL when string is empty, as before.
Expand Down
7 changes: 5 additions & 2 deletions app/views/active_scaffold_overrides/_base_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@
columns ||= action_config.columns unless local_assigns.has_key? :columns
persistent ||= action_config.persistent unless local_assigns.has_key? :persistent
unless local_assigns.has_key? :floating_footer
floating_footer ||= action_config.floating_footer if action_config.respond_to? :floating_footer
floating_footer = action_config.floating_footer if action_config.respond_to? :floating_footer
end
unless local_assigns.has_key? :add_locking_column
add_locking_column = action_config.add_locking_column if action_config.respond_to? :add_locking_column
end
else
multipart ||= false
Expand Down Expand Up @@ -39,7 +42,7 @@ else
form_tag url_options, options
end
-%>

<%= hidden_field :record, @record.class.locking_column if add_locking_column && @record.persisted? && @record.locking_enabled? %>
<h4><%= headline -%></h4>

<div id="<%= element_messages_id(:action => form_action) %>" class="messages-container">
Expand Down
4 changes: 4 additions & 0 deletions lib/active_scaffold/actions/update.rb
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ def update_save(attributes: params[:record], no_record_param_update: false)
rescue ActiveRecord::StaleObjectError
@record.errors.add(:base, as_(:version_inconsistency))
self.successful = false
on_stale_object_error(@record)
rescue ActiveRecord::RecordNotSaved => exception
logger.warn do
"\n\n#{exception.class} (#{exception.message}):\n " +
Expand Down Expand Up @@ -201,6 +202,9 @@ def before_update_save(record); end
# override this method if you want to do something after the save
def after_update_save(record); end

# override this method if you want to do something when stale object error is raised
def on_stale_object_error(record); end

# should we refresh whole list after update operation
def update_refresh_list?
active_scaffold_config.update.refresh_list
Expand Down
7 changes: 7 additions & 0 deletions lib/active_scaffold/attribute_params.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ def multi_parameter_attributes(attributes)
end
end

def assign_locking_column(parent_record, attributes)
return unless parent_record.persisted? && parent_record.locking_enabled? &&
attributes.include?(parent_record.class.locking_column)
parent_record.write_attribute parent_record.class.locking_column, attributes[parent_record.class.locking_column]
end

# Takes attributes (as from params[:record]) and applies them to the parent_record. Also looks for
# association attributes and attempts to instantiate them as associated objects.
#
Expand All @@ -59,6 +65,7 @@ def update_record_from_params(parent_record, columns, attributes, avoid_changes
return parent_record unless parent_record.authorized_for?(:crud_type => crud_type)

multi_parameter_attrs = multi_parameter_attributes(attributes)
assign_locking_column(parent_record, attributes)

columns.each_column(for: parent_record, crud_type: crud_type, flatten: true) do |column|
# Set any passthrough parameters that may be associated with this column (ie, file column "keep" and "temp" attributes)
Expand Down
8 changes: 7 additions & 1 deletion lib/active_scaffold/config/update.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class Update < ActiveScaffold::Config::Form
def initialize(core_config)
super
self.nested_links = self.class.nested_links
self.add_locking_column = self.class.add_locking_column
end

# global level configuration
Expand All @@ -21,20 +22,25 @@ def self.link=(val)
cattr_accessor :nested_links, instance_accessor: false
@@nested_links = false

cattr_accessor :add_locking_column, instance_accessor: false
@@add_locking_column = true

columns_accessor :columns, :copy => :create

# instance-level configuration
# ----------------------------

attr_accessor :nested_links

attr_accessor :add_locking_column

attr_writer :hide_nested_column
def hide_nested_column
@hide_nested_column.nil? ? true : @hide_nested_column
end

UserSettings.class_eval do
user_attr :nested_links, :hide_nested_column
user_attr :nested_links, :hide_nested_column, :add_locking_column
end
end
end

0 comments on commit da0636a

Please sign in to comment.