fix: Annotaterb model annotation incomplete migration (#13132)

This pull request fixes the model annotation tooling due to previous
incomplete migration from `annotate` to `annotaterb` gem (#12600). It
also improves the handling of serialized values in the
`InstallationConfig` model by ensuring a default value is set,
simplifying the code, and removing a workaround for YAML
deserialization.

**Annotation tooling updates:**

* Added `.annotaterb.yml` to configure the `annotate_rb` gem with
project-specific options, centralizing annotation settings.
* Replaced the custom `auto_annotate_models.rake` task with the standard
rake task from `annotate_rb`, and added `lib/tasks/annotate_rb.rake` to
load annotation tasks in development environments.
[[1]](diffhunk://#diff-9450d2359e45f1db407b3871dde787a25d60bb721aed179a65ffd2692e95fb4bL1-L61)
[[2]](diffhunk://#diff-578cdfc7ad56637e42472ea891ea286dff8803d9a1750afdbfeafec164d9b8b2R1-R8)

**Model serialization improvements:**

* Updated the `InstallationConfig` model to set a default value for the
`serialized_value` attribute, ensuring it always has a hash with
indifferent access and removing the need for a deserialization
workaround in the `value` method.
[[1]](diffhunk://#diff-b4bdde42c1ad0f584073818bd43dbd865b1b3b50d4701b131979f900d7c68297L22-R22)
[[2]](diffhunk://#diff-b4bdde42c1ad0f584073818bd43dbd865b1b3b50d4701b131979f900d7c68297L36-L39)

---------

Co-authored-by: Sojan Jose <sojan@pepalo.com>
This commit is contained in:
Mazen Khalil
2026-03-26 03:51:06 +03:00
committed by GitHub
parent ecc66e064d
commit e0e321b8e2
9 changed files with 125 additions and 99 deletions

65
.annotaterb.yml Normal file
View File

@@ -0,0 +1,65 @@
---
:position: before
:position_in_additional_file_patterns: before
:position_in_class: before
:position_in_factory: before
:position_in_fixture: before
:position_in_routes: before
:position_in_serializer: before
:position_in_test: before
:classified_sort: true
:exclude_controllers: true
:exclude_factories: true
:exclude_fixtures: true
:exclude_helpers: true
:exclude_scaffolds: true
:exclude_serializers: true
:exclude_sti_subclasses: false
:exclude_tests: true
:force: false
:format_markdown: false
:format_rdoc: false
:format_yard: false
:frozen: false
:grouped_polymorphic: false
:ignore_model_sub_dir: false
:ignore_unknown_models: false
:include_version: false
:show_check_constraints: false
:show_complete_foreign_keys: false
:show_foreign_keys: true
:show_indexes: true
:show_indexes_include: false
:simple_indexes: false
:sort: false
:timestamp: false
:trace: false
:with_comment: true
:with_column_comments: true
:with_table_comments: true
:position_of_column_comment: :with_name
:active_admin: false
:command:
:debug: false
:hide_default_column_types: json,jsonb,hstore
:hide_limit_column_types: integer,bigint,boolean
:timestamp_columns:
- created_at
- updated_at
:ignore_columns:
:ignore_routes:
:models: true
:routes: false
:skip_on_db_migrate: false
:target_action: :do_annotations
:wrapper:
:wrapper_close:
:wrapper_open:
:classes_default_to_s: []
:additional_file_patterns: []
:model_dir:
- app/models
- enterprise/app/models
:require: []
:root_dir:
- ''

View File

@@ -2,24 +2,28 @@
# #
# Table name: csat_survey_responses # Table name: csat_survey_responses
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# feedback_message :text # csat_review_notes :text
# rating :integer not null # feedback_message :text
# created_at :datetime not null # rating :integer not null
# updated_at :datetime not null # review_notes_updated_at :datetime
# account_id :bigint not null # created_at :datetime not null
# assigned_agent_id :bigint # updated_at :datetime not null
# contact_id :bigint not null # account_id :bigint not null
# conversation_id :bigint not null # assigned_agent_id :bigint
# message_id :bigint not null # contact_id :bigint not null
# conversation_id :bigint not null
# message_id :bigint not null
# review_notes_updated_by_id :bigint
# #
# Indexes # Indexes
# #
# index_csat_survey_responses_on_account_id (account_id) # index_csat_survey_responses_on_account_id (account_id)
# index_csat_survey_responses_on_assigned_agent_id (assigned_agent_id) # index_csat_survey_responses_on_assigned_agent_id (assigned_agent_id)
# index_csat_survey_responses_on_contact_id (contact_id) # index_csat_survey_responses_on_contact_id (contact_id)
# index_csat_survey_responses_on_conversation_id (conversation_id) # index_csat_survey_responses_on_conversation_id (conversation_id)
# index_csat_survey_responses_on_message_id (message_id) UNIQUE # index_csat_survey_responses_on_message_id (message_id) UNIQUE
# index_csat_survey_responses_on_review_notes_updated_by_id (review_notes_updated_by_id)
# #
class CsatSurveyResponse < ApplicationRecord class CsatSurveyResponse < ApplicationRecord
belongs_to :account belongs_to :account

View File

@@ -19,7 +19,7 @@ class InstallationConfig < ApplicationRecord
# https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017 # https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017
# FIX ME : fixes breakage of installation config. we need to migrate. # FIX ME : fixes breakage of installation config. we need to migrate.
# Fix configuration in application.rb # Fix configuration in application.rb
serialize :serialized_value, coder: YAML, type: ActiveSupport::HashWithIndifferentAccess serialize :serialized_value, coder: YAML, type: ActiveSupport::HashWithIndifferentAccess, default: {}.with_indifferent_access
before_validation :set_lock before_validation :set_lock
validates :name, presence: true validates :name, presence: true
@@ -33,10 +33,6 @@ class InstallationConfig < ApplicationRecord
after_commit :clear_cache after_commit :clear_cache
def value def value
# This is an extra hack again cause of the YAML serialization, in case of new object initialization in super admin
# It was throwing error as the default value of column '{}' was failing in deserialization.
return {}.with_indifferent_access if new_record? && @attributes['serialized_value']&.value_before_type_cast == '{}'
serialized_value[:value] serialized_value[:value]
end end

View File

@@ -17,13 +17,14 @@
# #
# Indexes # Indexes
# #
# index_reporting_events_on_account_id (account_id) # index_reporting_events_for_response_distribution (account_id,name,inbox_id,created_at)
# index_reporting_events_on_conversation_id (conversation_id) # index_reporting_events_on_account_id (account_id)
# index_reporting_events_on_created_at (created_at) # index_reporting_events_on_conversation_id (conversation_id)
# index_reporting_events_on_inbox_id (inbox_id) # index_reporting_events_on_created_at (created_at)
# index_reporting_events_on_name (name) # index_reporting_events_on_inbox_id (inbox_id)
# index_reporting_events_on_user_id (user_id) # index_reporting_events_on_name (name)
# reporting_events__account_id__name__created_at (account_id,name,created_at) # index_reporting_events_on_user_id (user_id)
# reporting_events__account_id__name__created_at (account_id,name,created_at)
# #
class ReportingEvent < ApplicationRecord class ReportingEvent < ApplicationRecord

View File

@@ -2,17 +2,17 @@
# #
# Table name: reporting_events_rollups # Table name: reporting_events_rollups
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# count :bigint default(0), not null # count :bigint default(0), not null
# date :date not null # date :date not null
# dimension_id :bigint not null # dimension_type :string not null
# dimension_type :string not null # metric :string not null
# metric :string not null # sum_value :float default(0.0), not null
# sum_value :float default(0.0), not null # sum_value_business_hours :float default(0.0), not null
# sum_value_business_hours :float default(0.0), not null # created_at :datetime not null
# created_at :datetime not null # updated_at :datetime not null
# updated_at :datetime not null # account_id :integer not null
# account_id :integer not null # dimension_id :bigint not null
# #
# Indexes # Indexes
# #

View File

@@ -4,6 +4,7 @@
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# name :string # name :string
# secret :string
# subscriptions :jsonb # subscriptions :jsonb
# url :text # url :text
# webhook_type :integer default("account_type") # webhook_type :integer default("account_type")

View File

@@ -0,0 +1,8 @@
# This rake task was added by annotate_rb gem.
# Can set `ANNOTATERB_SKIP_ON_DB_TASKS` to be anything to skip this
if Rails.env.development? && ENV['ANNOTATERB_SKIP_ON_DB_TASKS'].nil?
require 'annotate_rb'
AnnotateRb::Core.load_rake_tasks
end

View File

@@ -1,61 +0,0 @@
# NOTE: only doing this in development as some production environments (Heroku)
# NOTE: are sensitive to local FS writes, and besides -- it's just not proper
# NOTE: to have a dev-mode tool do its thing in production.
if Rails.env.development?
require 'annotate_rb'
AnnotateRb::Core.load_rake_tasks
task :set_annotation_options do
# You can override any of these by setting an environment variable of the
# same name.
AnnotateRb::Options.set_defaults(
'additional_file_patterns' => [],
'routes' => 'false',
'models' => 'true',
'position_in_routes' => 'before',
'position_in_class' => 'before',
'position_in_test' => 'before',
'position_in_fixture' => 'before',
'position_in_factory' => 'before',
'position_in_serializer' => 'before',
'show_foreign_keys' => 'true',
'show_complete_foreign_keys' => 'false',
'show_indexes' => 'true',
'simple_indexes' => 'false',
'model_dir' => [
'app/models',
'enterprise/app/models',
],
'root_dir' => '',
'include_version' => 'false',
'require' => '',
'exclude_tests' => 'true',
'exclude_fixtures' => 'true',
'exclude_factories' => 'true',
'exclude_serializers' => 'true',
'exclude_scaffolds' => 'true',
'exclude_controllers' => 'true',
'exclude_helpers' => 'true',
'exclude_sti_subclasses' => 'false',
'ignore_model_sub_dir' => 'false',
'ignore_columns' => nil,
'ignore_routes' => nil,
'ignore_unknown_models' => 'false',
'hide_limit_column_types' => 'integer,bigint,boolean',
'hide_default_column_types' => 'json,jsonb,hstore',
'skip_on_db_migrate' => 'false',
'format_bare' => 'true',
'format_rdoc' => 'false',
'format_markdown' => 'false',
'sort' => 'false',
'force' => 'false',
'frozen' => 'false',
'classified_sort' => 'true',
'trace' => 'false',
'wrapper_open' => nil,
'wrapper_close' => nil,
'with_comment' => 'true'
)
end
end

View File

@@ -3,5 +3,17 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe InstallationConfig do RSpec.describe InstallationConfig do
subject(:installation_config) { described_class.new(name: 'INSTALLATION_NAME') }
it { is_expected.to validate_presence_of(:name) } it { is_expected.to validate_presence_of(:name) }
describe 'new record defaults' do
it 'initializes serialized_value with indifferent access' do
expect(installation_config.serialized_value).to eq({}.with_indifferent_access)
end
it 'returns nil for value before assignment' do
expect(installation_config.value).to be_nil
end
end
end end