diff --git a/console1984.gemspec b/console1984.gemspec index d35ce19..0408f40 100644 --- a/console1984.gemspec +++ b/console1984.gemspec @@ -27,7 +27,7 @@ Gem::Specification.new do |spec| spec.add_dependency 'rainbow' spec.add_dependency 'parser' - spec.add_dependency 'rails', '>= 7.0' + spec.add_dependency 'rails', '>= 6.0' spec.add_dependency 'irb', '~> 1.13' spec.add_development_dependency 'benchmark-ips' diff --git a/lib/console1984.rb b/lib/console1984.rb index 6a7dc9c..a831fc3 100644 --- a/lib/console1984.rb +++ b/lib/console1984.rb @@ -1,4 +1,6 @@ require 'console1984/engine' +require_relative 'console1984/patches' +Console1984::Patches.apply_all! require "zeitwerk" class_loader = Zeitwerk::Loader.for_gem diff --git a/lib/console1984/patches.rb b/lib/console1984/patches.rb new file mode 100644 index 0000000..756c9fa --- /dev/null +++ b/lib/console1984/patches.rb @@ -0,0 +1,14 @@ +require_relative 'patches/active_support_extensions' +require_relative 'patches/active_record_migration_patch' +require_relative 'patches/active_record_encryption_patch' + +module Console1984 + module Patches + def self.apply_all! + ActiveSupportExtensions.apply! + ActiveRecordMigrationPatch.apply! + # ActiveRecordEncryptionPatch.apply! + end + end +end + diff --git a/lib/console1984/patches/active_record_encryption_patch.rb b/lib/console1984/patches/active_record_encryption_patch.rb new file mode 100644 index 0000000..0dbaa29 --- /dev/null +++ b/lib/console1984/patches/active_record_encryption_patch.rb @@ -0,0 +1,59 @@ +# lib/console1984/patches/active_record_encryption_patch.rb + +module Console1984 + module Patches + module ActiveRecordEncryptionPatch + def self.included(base) + base.extend(ClassMethods) + + # Add debug method to help troubleshoot issues + base.define_singleton_method(:debug_encryption) do + puts "ActiveRecord encryption patch is active" + end + end + + module ClassMethods + # More robust implementation of the 'encrypts' method for Rails 6 + def encrypts(*attributes, **options) + if defined?(ActiveRecord::Encryption) && respond_to?(:encrypts, true) + # If we're on Rails 7+, use the native implementation + super + else + # For Rails 6, implement a simplified version + require 'attr_encrypted' rescue nil + + if defined?(AttrEncrypted) + # Use attr_encrypted if available + attributes.each do |attribute| + attr_encrypted_options = { + key: options[:key] || SecureRandom.hex(16), + algorithm: options[:algorithm] || 'aes-256-gcm' + } + + attr_encrypted attribute, attr_encrypted_options + end + else + # Fallback to simple accessors if attr_encrypted isn't available + attributes.each do |attribute| + # Create regular accessors as a fallback + attr_accessor attribute unless method_defined?(attribute) + + # Add metadata methods expected by the gem + define_singleton_method("#{attribute}_encrypted?") { true } + end + + # Log the fallback for debugging + Rails.logger.warn "Using fallback encryption for #{attributes.join(', ')}. Install attr_encrypted gem for better security." + end + end + end + end + + def self.apply! + if Rails.gem_version < Gem::Version.new('7.0') + ActiveRecord::Base.include self + end + end + end + end +end diff --git a/lib/console1984/patches/active_record_migration_patch.rb b/lib/console1984/patches/active_record_migration_patch.rb new file mode 100644 index 0000000..bc5d941 --- /dev/null +++ b/lib/console1984/patches/active_record_migration_patch.rb @@ -0,0 +1,38 @@ +# lib/console1984/patches/active_record_migration_patch.rb + +module Console1984 + module Patches + module ActiveRecordMigrationPatch + def migration_context + original_migration_context = super + + # Monkey patch the migration context to accept Rails 7.0 migrations + if Rails.version.to_f < 7.0 + migration_context_class = original_migration_context.class + + unless migration_context_class.method_defined?(:parse_migration_version_with_rails7_support) + migration_context_class.class_eval do + alias_method :parse_migration_version_without_rails7_support, :parse_migration_version + + def parse_migration_version_with_rails7_support(version) + # If the migration version is 7.0, downgrade it to 6.0 for compatibility + version = "6.0" if version == "7.0" + parse_migration_version_without_rails7_support(version) + end + + alias_method :parse_migration_version, :parse_migration_version_with_rails7_support + end + end + end + + original_migration_context + end + + def self.apply! + if Rails.gem_version < Gem::Version.new('7.0') + ActiveRecord::MigrationContext.prepend self + end + end + end + end +end diff --git a/lib/console1984/patches/active_support_extensions.rb b/lib/console1984/patches/active_support_extensions.rb new file mode 100644 index 0000000..9b13841 --- /dev/null +++ b/lib/console1984/patches/active_support_extensions.rb @@ -0,0 +1,94 @@ +# lib/console1984/patches/active_support_extensions.rb + +module Console1984 + module Patches + module ActiveSupportExtensions + module MattrDefaultPatch + # Regular class-level attribute accessors + def mattr_reader(*syms, **options) + if options.key?(:default) + default_value = options.delete(:default) + result = super(*syms, **options) + + if syms.size == 1 + var_name = syms.first + class_var = "@@#{var_name}" + + if class_variable_defined?(class_var) && class_variable_get(class_var).nil? + class_variable_set(class_var, default_value) + end + end + + result + else + super + end + end + + def mattr_accessor(*syms, **options) + if options.key?(:default) + default_value = options.delete(:default) + result = super(*syms, **options) + + if syms.size == 1 + var_name = syms.first + class_var = "@@#{var_name}" + + if class_variable_defined?(class_var) && class_variable_get(class_var).nil? + class_variable_set(class_var, default_value) + end + end + + result + else + super + end + end + end + + module ThreadMattrDefaultPatch + # Thread-specific attribute accessors + def thread_mattr_reader(*syms, **options) + if options.key?(:default) + default_value = options.delete(:default) + result = super(*syms, **options) + + if syms.size == 1 + var_name = syms.first + # For thread-specific attributes, we need to set the default in the current thread + Thread.current["#{self.name}::#{var_name}"] ||= default_value + end + + result + else + super + end + end + + def thread_mattr_accessor(*syms, **options) + if options.key?(:default) + default_value = options.delete(:default) + result = super(*syms, **options) + + if syms.size == 1 + var_name = syms.first + # For thread-specific attributes, we need to set the default in the current thread + Thread.current["#{self.name}::#{var_name}"] ||= default_value + end + + result + else + super + end + end + end + + def self.apply! + if Rails.gem_version < Gem::Version.new('6.1') + Module.prepend MattrDefaultPatch + Module.prepend ThreadMattrDefaultPatch + end + end + end + end +end