From 106bfd56dafbfdb178516541b70987c82b80c4e4 Mon Sep 17 00:00:00 2001 From: Denny Bresch Date: Wed, 31 Jul 2019 09:45:27 +0200 Subject: [PATCH] Fixes #2664 - ObjectManager::Attribute names collide with reserved application words ( e.g. `url`) and break functionalities --- app/models/object_manager/attribute.rb | 2 +- .../20190724000001_rename_reserved_words.rb | 29 +++++++++++++++++++ spec/models/object_manager/attribute_spec.rb | 10 ++++--- 3 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 db/migrate/20190724000001_rename_reserved_words.rb diff --git a/app/models/object_manager/attribute.rb b/app/models/object_manager/attribute.rb index 1fdbb3572..ef9a7dad0 100644 --- a/app/models/object_manager/attribute.rb +++ b/app/models/object_manager/attribute.rb @@ -901,7 +901,7 @@ is certain attribute used by triggers, overviews or schedulers raise 'At least one letters is needed' if !name.match?(/[a-z]/) # do not allow model method names as attributes - reserved_words = %w[destroy true false integer select drop create alter index table varchar blob date datetime timestamp] + reserved_words = %w[destroy true false integer select drop create alter index table varchar blob date datetime timestamp url icon initials avatar permission validate subscribe unsubscribe translate search] raise "#{name} is a reserved word, please choose a different one" if name.match?(/^(#{reserved_words.join('|')})$/) # fixes issue #2236 - Naming an attribute "attribute" causes ActiveRecord failure diff --git a/db/migrate/20190724000001_rename_reserved_words.rb b/db/migrate/20190724000001_rename_reserved_words.rb new file mode 100644 index 000000000..865097eaa --- /dev/null +++ b/db/migrate/20190724000001_rename_reserved_words.rb @@ -0,0 +1,29 @@ +class RenameReservedWords < ActiveRecord::Migration[5.1] + def up + return if !Setting.find_by(name: 'system_init_done') + + models = ObjectManager.list_objects.map(&:underscore).map { |object| object.tr('_', '/') }.map(&:classify).map(&:constantize) + + reserved_words = %w[url icon initials avatar permission validate subscribe unsubscribe translate search] + models.each do |model| + + reserved_words.each do |reserved_word| + + next if ActiveRecord::Base.connection.columns(model.table_name).map(&:name).exclude?(reserved_word) + + sanitized_name = "_#{reserved_word}" + + ActiveRecord::Migration.rename_column(model.table_name.to_sym, reserved_word.to_sym, sanitized_name.to_sym) + model.reset_column_information + + attribute = ObjectManager::Attribute.get( + object: model.to_app_model, + name: reserved_word, + ) + next if !attribute + + attribute.update!(name: sanitized_name) + end + end + end +end diff --git a/spec/models/object_manager/attribute_spec.rb b/spec/models/object_manager/attribute_spec.rb index c886b2168..5be19f6a4 100644 --- a/spec/models/object_manager/attribute_spec.rb +++ b/spec/models/object_manager/attribute_spec.rb @@ -57,10 +57,12 @@ RSpec.describe ObjectManager::Attribute, type: :model do end.to raise_error 'attribute is a reserved word, please choose a different one' end - it 'rejects Zammad reserved word "table"' do - expect do - ObjectManager::Attribute.add attributes_for :object_manager_attribute_text, name: 'table' - end.to raise_error 'table is a reserved word, please choose a different one' + %w[destroy true false integer select drop create alter index table varchar blob date datetime timestamp url icon initials avatar permission validate subscribe unsubscribe translate search].each do |reserved_word| + it "rejects Zammad reserved word '#{reserved_word}'" do + expect do + ObjectManager::Attribute.add attributes_for :object_manager_attribute_text, name: reserved_word + end.to raise_error "#{reserved_word} is a reserved word, please choose a different one" + end end it 'rejects duplicate attribute name of conflicting types' do