Fixed issue #2099 - Changing data type of new object attributes will lead to errors.
This commit is contained in:
parent
4bae98e55a
commit
40a663198c
7 changed files with 310 additions and 82 deletions
|
@ -28,6 +28,12 @@ class App.UiElement.object_manager_attribute extends App.UiElement.ApplicationUi
|
||||||
boolean: 'Boolean'
|
boolean: 'Boolean'
|
||||||
integer: 'Integer'
|
integer: 'Integer'
|
||||||
|
|
||||||
|
# if attribute already exists, do not allow to change it anymore
|
||||||
|
if params.data_type
|
||||||
|
for key, value of options
|
||||||
|
if key isnt params.data_type
|
||||||
|
delete options[key]
|
||||||
|
|
||||||
configureAttributes = [
|
configureAttributes = [
|
||||||
{ name: attribute.name, display: '', tag: 'select', null: false, options: options, translate: true, default: 'input', disabled: attribute.disabled },
|
{ name: attribute.name, display: '', tag: 'select', null: false, options: options, translate: true, default: 'input', disabled: attribute.disabled },
|
||||||
]
|
]
|
||||||
|
|
|
@ -12,6 +12,9 @@ class ObjectManager::Attribute < ApplicationModel
|
||||||
store :data_option
|
store :data_option
|
||||||
store :data_option_new
|
store :data_option_new
|
||||||
|
|
||||||
|
before_create :check_datatype
|
||||||
|
before_update :check_datatype, :verify_possible_type_change
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|
||||||
list of all attributes
|
list of all attributes
|
||||||
|
@ -324,7 +327,6 @@ possible types
|
||||||
record.check_editable
|
record.check_editable
|
||||||
record.check_name
|
record.check_name
|
||||||
end
|
end
|
||||||
record.check_datatype
|
|
||||||
record.save!
|
record.save!
|
||||||
return record
|
return record
|
||||||
end
|
end
|
||||||
|
@ -344,7 +346,6 @@ possible types
|
||||||
record.check_editable
|
record.check_editable
|
||||||
record.check_name
|
record.check_name
|
||||||
end
|
end
|
||||||
record.check_datatype
|
|
||||||
record.save!
|
record.save!
|
||||||
record
|
record
|
||||||
end
|
end
|
||||||
|
@ -878,7 +879,13 @@ is certain attribute used by triggers, overviews or schedulers
|
||||||
raise 'Attribute not editable!'
|
raise 'Attribute not editable!'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
def check_datatype
|
def check_datatype
|
||||||
|
local_data_option = data_option
|
||||||
|
if to_config == true
|
||||||
|
local_data_option = data_option_new
|
||||||
|
end
|
||||||
if !data_type
|
if !data_type
|
||||||
raise 'Need data_type param'
|
raise 'Need data_type param'
|
||||||
end
|
end
|
||||||
|
@ -886,62 +893,76 @@ is certain attribute used by triggers, overviews or schedulers
|
||||||
raise "Invalid data_type param '#{data_type}'"
|
raise "Invalid data_type param '#{data_type}'"
|
||||||
end
|
end
|
||||||
|
|
||||||
if !data_option
|
if local_data_option.blank?
|
||||||
raise 'Need data_type param'
|
raise 'Need data_option param'
|
||||||
end
|
end
|
||||||
if data_option[:null].nil?
|
if local_data_option[:null].nil?
|
||||||
raise 'Need data_option[:null] param with true or false'
|
raise 'Need data_option[:null] param with true or false'
|
||||||
end
|
end
|
||||||
|
|
||||||
# validate data_option
|
# validate data_option
|
||||||
if data_type == 'input'
|
if data_type == 'input'
|
||||||
raise 'Need data_option[:type] param e. g. (text|password|tel|fax|email|url)' if !data_option[:type]
|
raise 'Need data_option[:type] param e. g. (text|password|tel|fax|email|url)' if !local_data_option[:type]
|
||||||
raise "Invalid data_option[:type] param '#{data_option[:type]}' (text|password|tel|fax|email|url)" if data_option[:type] !~ /^(text|password|tel|fax|email|url)$/
|
raise "Invalid data_option[:type] param '#{local_data_option[:type]}' (text|password|tel|fax|email|url)" if local_data_option[:type] !~ /^(text|password|tel|fax|email|url)$/
|
||||||
raise 'Need data_option[:maxlength] param' if !data_option[:maxlength]
|
raise 'Need data_option[:maxlength] param' if !local_data_option[:maxlength]
|
||||||
raise "Invalid data_option[:maxlength] param #{data_option[:maxlength]}" if data_option[:maxlength].to_s !~ /^\d+?$/
|
raise "Invalid data_option[:maxlength] param #{local_data_option[:maxlength]}" if local_data_option[:maxlength].to_s !~ /^\d+?$/
|
||||||
end
|
end
|
||||||
|
|
||||||
if data_type == 'richtext'
|
if data_type == 'richtext'
|
||||||
raise 'Need data_option[:maxlength] param' if !data_option[:maxlength]
|
raise 'Need data_option[:maxlength] param' if !local_data_option[:maxlength]
|
||||||
raise "Invalid data_option[:maxlength] param #{data_option[:maxlength]}" if data_option[:maxlength].to_s !~ /^\d+?$/
|
raise "Invalid data_option[:maxlength] param #{local_data_option[:maxlength]}" if local_data_option[:maxlength].to_s !~ /^\d+?$/
|
||||||
end
|
end
|
||||||
|
|
||||||
if data_type == 'integer'
|
if data_type == 'integer'
|
||||||
%i[min max].each do |item|
|
%i[min max].each do |item|
|
||||||
raise "Need data_option[#{item.inspect}] param" if !data_option[item]
|
raise "Need data_option[#{item.inspect}] param" if !local_data_option[item]
|
||||||
raise "Invalid data_option[#{item.inspect}] param #{data_option[item]}" if data_option[item].to_s !~ /^\d+?$/
|
raise "Invalid data_option[#{item.inspect}] param #{data_option[item]}" if local_data_option[item].to_s !~ /^\d+?$/
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if data_type == 'select' || data_type == 'tree_select' || data_type == 'checkbox'
|
if data_type == 'select' || data_type == 'tree_select' || data_type == 'checkbox'
|
||||||
raise 'Need data_option[:default] param' if !data_option.key?(:default)
|
raise 'Need data_option[:default] param' if !local_data_option.key?(:default)
|
||||||
raise 'Invalid data_option[:options] or data_option[:relation] param' if data_option[:options].nil? && data_option[:relation].nil?
|
raise 'Invalid data_option[:options] or data_option[:relation] param' if local_data_option[:options].nil? && local_data_option[:relation].nil?
|
||||||
if !data_option.key?(:maxlength)
|
if !local_data_option.key?(:maxlength)
|
||||||
data_option[:maxlength] = 255
|
local_data_option[:maxlength] = 255
|
||||||
end
|
end
|
||||||
if !data_option.key?(:nulloption)
|
if !local_data_option.key?(:nulloption)
|
||||||
data_option[:nulloption] = true
|
local_data_option[:nulloption] = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if data_type == 'boolean'
|
if data_type == 'boolean'
|
||||||
raise 'Need data_option[:default] param true|false|undefined' if !data_option.key?(:default)
|
raise 'Need data_option[:default] param true|false|undefined' if !local_data_option.key?(:default)
|
||||||
raise 'Invalid data_option[:options] param' if data_option[:options].nil?
|
raise 'Invalid data_option[:options] param' if local_data_option[:options].nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
if data_type == 'datetime'
|
if data_type == 'datetime'
|
||||||
raise 'Need data_option[:future] param true|false' if data_option[:future].nil?
|
raise 'Need data_option[:future] param true|false' if local_data_option[:future].nil?
|
||||||
raise 'Need data_option[:past] param true|false' if data_option[:past].nil?
|
raise 'Need data_option[:past] param true|false' if local_data_option[:past].nil?
|
||||||
raise 'Need data_option[:diff] param in hours' if data_option[:diff].nil?
|
raise 'Need data_option[:diff] param in hours' if local_data_option[:diff].nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
if data_type == 'date'
|
if data_type == 'date'
|
||||||
raise 'Need data_option[:future] param true|false' if data_option[:future].nil?
|
raise 'Need data_option[:future] param true|false' if local_data_option[:future].nil?
|
||||||
raise 'Need data_option[:past] param true|false' if data_option[:past].nil?
|
raise 'Need data_option[:past] param true|false' if local_data_option[:past].nil?
|
||||||
raise 'Need data_option[:diff] param in days' if data_option[:diff].nil?
|
raise 'Need data_option[:diff] param in days' if local_data_option[:diff].nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def verify_possible_type_change
|
||||||
|
return true if changes_to_save['data_type'].blank?
|
||||||
|
|
||||||
|
possible = {
|
||||||
|
'select' => %w[tree_select select input checkbox],
|
||||||
|
'tree_select' => %w[tree_select select input checkbox],
|
||||||
|
'checkbox' => %w[tree_select select input checkbox],
|
||||||
|
'input' => %w[tree_select select input checkbox],
|
||||||
|
}
|
||||||
|
|
||||||
|
return true if possible[changes_to_save['data_type'][0]]&.include?(changes_to_save['data_type'][1])
|
||||||
|
|
||||||
|
raise 'Can\'t be changed data_type of attribute. Drop the attribute and recreate it with new data_type.'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -41,32 +41,15 @@ RSpec.describe CheckForObjectAttributes, type: :db_migration do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context '[:data_option]' do
|
|
||||||
|
|
||||||
it 'ensures an empty Hash' do
|
|
||||||
attribute = create(:object_manager_attribute_text, data_option: nil)
|
|
||||||
migrate
|
|
||||||
attribute.reload
|
|
||||||
|
|
||||||
expect(attribute[:data_option]).to be_a(Hash)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context '[:data_option][:options]' do
|
context '[:data_option][:options]' do
|
||||||
|
|
||||||
it 'ensures an empty Hash' do
|
|
||||||
attribute = create(:object_manager_attribute_text, data_option: {})
|
|
||||||
migrate
|
|
||||||
attribute.reload
|
|
||||||
|
|
||||||
expect(attribute[:data_option][:options]).to be_a(Hash)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'converts String to Hash' do
|
it 'converts String to Hash' do
|
||||||
wrong = {
|
wrong = {
|
||||||
default: '',
|
default: '',
|
||||||
options: '',
|
options: '',
|
||||||
relation: '',
|
relation: '',
|
||||||
|
type: 'text',
|
||||||
|
maxlength: 255,
|
||||||
null: true
|
null: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +68,8 @@ RSpec.describe CheckForObjectAttributes, type: :db_migration do
|
||||||
wrong = {
|
wrong = {
|
||||||
default: '',
|
default: '',
|
||||||
options: {},
|
options: {},
|
||||||
|
type: 'text',
|
||||||
|
maxlength: 255,
|
||||||
null: true
|
null: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,6 +85,8 @@ RSpec.describe CheckForObjectAttributes, type: :db_migration do
|
||||||
default: '',
|
default: '',
|
||||||
options: {},
|
options: {},
|
||||||
relation: {},
|
relation: {},
|
||||||
|
type: 'text',
|
||||||
|
maxlength: 255,
|
||||||
null: true
|
null: true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -175,7 +175,7 @@ RSpec.describe Issue1660FixTreeSelectConfigurations, type: :db_migration do
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
attribute = create(:object_manager_attribute_tree_select, data_option: { options: broken })
|
attribute = create(:object_manager_attribute_tree_select, data_option: { options: broken, null: true, default: '' })
|
||||||
|
|
||||||
expect do
|
expect do
|
||||||
migrate
|
migrate
|
||||||
|
@ -192,18 +192,8 @@ RSpec.describe Issue1660FixTreeSelectConfigurations, type: :db_migration do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'skips blank data_option' do
|
|
||||||
attribute = create(:object_manager_attribute_tree_select, data_option: {})
|
|
||||||
|
|
||||||
expect do
|
|
||||||
migrate
|
|
||||||
end.not_to change {
|
|
||||||
attribute.reload.data_option
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'skips blank data_option options' do
|
it 'skips blank data_option options' do
|
||||||
attribute = create(:object_manager_attribute_tree_select, data_option: { options: [] })
|
attribute = create(:object_manager_attribute_tree_select, data_option: { options: [], null: true, default: '' })
|
||||||
|
|
||||||
expect do
|
expect do
|
||||||
migrate
|
migrate
|
||||||
|
|
|
@ -3610,7 +3610,10 @@ wait untill text in selector disabppears
|
||||||
css: '.content.active a[href="#system/object_manager"]',
|
css: '.content.active a[href="#system/object_manager"]',
|
||||||
mute_log: true,
|
mute_log: true,
|
||||||
)
|
)
|
||||||
sleep 4
|
watch_for(
|
||||||
|
browser: instance,
|
||||||
|
css: '.content.active .js-new',
|
||||||
|
)
|
||||||
click(
|
click(
|
||||||
browser: instance,
|
browser: instance,
|
||||||
css: '.content.active .js-new',
|
css: '.content.active .js-new',
|
||||||
|
@ -3745,8 +3748,10 @@ wait untill text in selector disabppears
|
||||||
css: '.content.active a[href="#system/object_manager"]',
|
css: '.content.active a[href="#system/object_manager"]',
|
||||||
mute_log: true,
|
mute_log: true,
|
||||||
)
|
)
|
||||||
sleep 4
|
watch_for(
|
||||||
|
browser: instance,
|
||||||
|
css: '.content.active .js-new',
|
||||||
|
)
|
||||||
instance.execute_script("$(\".content.active td:contains('#{data[:name]}')\").first().click()")
|
instance.execute_script("$(\".content.active td:contains('#{data[:name]}')\").first().click()")
|
||||||
modal_ready(browser: instance)
|
modal_ready(browser: instance)
|
||||||
element = instance.find_elements(css: '.modal input[name=display]')[0]
|
element = instance.find_elements(css: '.modal input[name=display]')[0]
|
||||||
|
@ -3758,6 +3763,12 @@ wait untill text in selector disabppears
|
||||||
value: data[:data_type],
|
value: data[:data_type],
|
||||||
mute_log: true,
|
mute_log: true,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# if attribute is created, do not be able to select other types anymore
|
||||||
|
if instance.find_elements(css: '.modal select[name="data_type"] option').count > 1
|
||||||
|
assert(false, 'able to change the data_type of existing attribute which should not be allowed')
|
||||||
|
end
|
||||||
|
|
||||||
if data[:data_option]
|
if data[:data_option]
|
||||||
if data[:data_option][:options]
|
if data[:data_option][:options]
|
||||||
if data[:data_type] == 'Boolean'
|
if data[:data_type] == 'Boolean'
|
||||||
|
|
|
@ -1014,4 +1014,138 @@ class ObjectManagerAttributesControllerTest < ActionDispatch::IntegrationTest
|
||||||
assert @response.body.include?('cannot be deleted!')
|
assert @response.body.include?('cannot be deleted!')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test '07 verify if attribute type can not be changed' do
|
||||||
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin@example.com', 'adminpw')
|
||||||
|
|
||||||
|
params = {
|
||||||
|
'name': "customerdescription_#{rand(999_999_999)}",
|
||||||
|
'object': 'Ticket',
|
||||||
|
'display': "custom description #{rand(999_999_999)}",
|
||||||
|
'active': true,
|
||||||
|
'data_type': 'boolean',
|
||||||
|
'data_option': {
|
||||||
|
'options': {
|
||||||
|
'true': '',
|
||||||
|
'false': '',
|
||||||
|
},
|
||||||
|
'default': 'false',
|
||||||
|
'screens': {
|
||||||
|
'create_middle': {
|
||||||
|
'ticket.customer': {
|
||||||
|
'shown': true,
|
||||||
|
'item_class': 'column'
|
||||||
|
},
|
||||||
|
'ticket.agent': {
|
||||||
|
'shown': true,
|
||||||
|
'item_class': 'column'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'edit': {
|
||||||
|
'ticket.customer': {
|
||||||
|
'shown': true
|
||||||
|
},
|
||||||
|
'ticket.agent': {
|
||||||
|
'shown': true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials)
|
||||||
|
|
||||||
|
assert_response(201) # created
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
|
||||||
|
assert(result)
|
||||||
|
assert_not(result['data_option']['default'])
|
||||||
|
assert_equal(result['data_option']['default'], false)
|
||||||
|
assert_equal(result['data_type'], 'boolean')
|
||||||
|
|
||||||
|
migration = ObjectManager::Attribute.migration_execute
|
||||||
|
assert_equal(migration, true)
|
||||||
|
|
||||||
|
params['data_type'] = 'input'
|
||||||
|
params['data_option'] = {
|
||||||
|
'default': 'test',
|
||||||
|
'type': 'text',
|
||||||
|
'maxlength': 120
|
||||||
|
}
|
||||||
|
|
||||||
|
put "/api/v1/object_manager_attributes/#{result['id']}", params: params.to_json, headers: @headers.merge('Authorization' => credentials)
|
||||||
|
assert_response(422)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert(result)
|
||||||
|
assert(result['error']['Can\'t be changed data_type of attribute. Drop the attribute and recreate it with new data_type.'])
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
test '08 verify if attribute type can be changed' do
|
||||||
|
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin@example.com', 'adminpw')
|
||||||
|
|
||||||
|
params = {
|
||||||
|
'name': "customerdescription_#{rand(999_999_999)}",
|
||||||
|
'object': 'Ticket',
|
||||||
|
'display': "custom description #{rand(999_999_999)}",
|
||||||
|
'active': true,
|
||||||
|
'data_type': 'input',
|
||||||
|
'data_option': {
|
||||||
|
'default': 'test',
|
||||||
|
'type': 'text',
|
||||||
|
'maxlength': 120,
|
||||||
|
},
|
||||||
|
'screens': {
|
||||||
|
'create_middle': {
|
||||||
|
'ticket.customer': {
|
||||||
|
'shown': true,
|
||||||
|
'item_class': 'column'
|
||||||
|
},
|
||||||
|
'ticket.agent': {
|
||||||
|
'shown': true,
|
||||||
|
'item_class': 'column'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'edit': {
|
||||||
|
'ticket.customer': {
|
||||||
|
'shown': true
|
||||||
|
},
|
||||||
|
'ticket.agent': {
|
||||||
|
'shown': true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
post '/api/v1/object_manager_attributes', params: params.to_json, headers: @headers.merge('Authorization' => credentials)
|
||||||
|
|
||||||
|
assert_response(201) # created
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
|
||||||
|
assert(result)
|
||||||
|
assert_equal(result['data_option']['default'], 'test')
|
||||||
|
assert_equal(result['data_type'], 'input')
|
||||||
|
|
||||||
|
migration = ObjectManager::Attribute.migration_execute
|
||||||
|
assert_equal(migration, true)
|
||||||
|
|
||||||
|
params['data_type'] = 'select'
|
||||||
|
params['data_option'] = {
|
||||||
|
'default': 'fuu',
|
||||||
|
'options': {
|
||||||
|
'key1': 'foo',
|
||||||
|
'key2': 'fuu',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
put "/api/v1/object_manager_attributes/#{result['id']}", params: params.to_json, headers: @headers.merge('Authorization' => credentials)
|
||||||
|
|
||||||
|
assert_response(200)
|
||||||
|
result = JSON.parse(@response.body)
|
||||||
|
assert(result)
|
||||||
|
assert_equal(result['data_option']['default'], 'test')
|
||||||
|
assert_equal(result['data_option_new']['default'], 'fuu')
|
||||||
|
assert_equal(result['data_type'], 'select')
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -788,4 +788,83 @@ class ObjectManagerTest < ActiveSupport::TestCase
|
||||||
assert_equal(1, overview[:count])
|
assert_equal(1, overview[:count])
|
||||||
assert_equal(ticket1.id, overview[:tickets][0][:id])
|
assert_equal(ticket1.id, overview[:tickets][0][:id])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test 'd object manager attribute - update attribute type' do
|
||||||
|
|
||||||
|
attribute1 = ObjectManager::Attribute.add(
|
||||||
|
object: 'Ticket',
|
||||||
|
name: 'example_1',
|
||||||
|
display: 'example_1',
|
||||||
|
data_type: 'input',
|
||||||
|
data_option: {
|
||||||
|
default: '',
|
||||||
|
maxlength: 200,
|
||||||
|
type: 'text',
|
||||||
|
null: true,
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
active: true,
|
||||||
|
screens: {},
|
||||||
|
position: 20,
|
||||||
|
created_by_id: 1,
|
||||||
|
updated_by_id: 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert_equal(true, ObjectManager::Attribute.pending_migration?)
|
||||||
|
assert_equal(1, ObjectManager::Attribute.migrations.count)
|
||||||
|
|
||||||
|
assert(ObjectManager::Attribute.migration_execute)
|
||||||
|
|
||||||
|
assert_raises(RuntimeError) do
|
||||||
|
ObjectManager::Attribute.add(
|
||||||
|
object: 'Ticket',
|
||||||
|
name: 'example_1',
|
||||||
|
display: 'example_1',
|
||||||
|
data_type: 'boolean',
|
||||||
|
data_option: {
|
||||||
|
default: true,
|
||||||
|
options: {
|
||||||
|
true: 'Yes',
|
||||||
|
false: 'No',
|
||||||
|
},
|
||||||
|
null: false,
|
||||||
|
},
|
||||||
|
active: true,
|
||||||
|
screens: {},
|
||||||
|
position: 200,
|
||||||
|
created_by_id: 1,
|
||||||
|
updated_by_id: 1,
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
attribute2 = ObjectManager::Attribute.add(
|
||||||
|
object: 'Ticket',
|
||||||
|
name: 'example_1',
|
||||||
|
display: 'example_1',
|
||||||
|
data_type: 'select',
|
||||||
|
data_option: {
|
||||||
|
default: '',
|
||||||
|
maxlength: 200,
|
||||||
|
type: 'text',
|
||||||
|
null: true,
|
||||||
|
options: {
|
||||||
|
aa: 'aa',
|
||||||
|
bb: 'bb',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
active: true,
|
||||||
|
screens: {},
|
||||||
|
position: 20,
|
||||||
|
created_by_id: 1,
|
||||||
|
updated_by_id: 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert_equal(attribute1.id, attribute2.id)
|
||||||
|
assert_equal(true, ObjectManager::Attribute.pending_migration?)
|
||||||
|
assert_equal(1, ObjectManager::Attribute.migrations.count)
|
||||||
|
|
||||||
|
assert(ObjectManager::Attribute.migration_execute)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue