├── .gitignore ├── lib ├── activerecord-create_decorator.rb └── activerecord │ └── abstract_adapter_ext.rb ├── Gemfile ├── renovate.json ├── spec ├── spec_helper.rb └── lib │ └── activerecord │ └── schema_statements_ext_spec.rb ├── activerecord-create_decorator.gemspec ├── LICENSE.txt └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | Gemfile.lock 3 | -------------------------------------------------------------------------------- /lib/activerecord-create_decorator.rb: -------------------------------------------------------------------------------- 1 | require 'activerecord/abstract_adapter_ext' 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | group :test do 6 | gem 'rspec', '~> 3.11.0' 7 | gem 'byebug' 8 | end -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "config:base" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'active_record' 2 | require_relative '../lib/activerecord/abstract_adapter_ext.rb' 3 | 4 | RSpec.configure do |config| 5 | config.order = "random" 6 | end 7 | -------------------------------------------------------------------------------- /activerecord-create_decorator.gemspec: -------------------------------------------------------------------------------- 1 | Gem::Specification.new do |s| 2 | s.name = 'activerecord-create_decorator' 3 | s.version = '0.1.2' 4 | s.author = 'GoDaddy' 5 | s.email = 'nemo-engg@godaddy.com' 6 | s.licenses = ['MIT'] 7 | s.summary = 'Applies connection-specific options when creating tables through ActiveRecord' 8 | s.description = '' 9 | s.homepage = 'https://github.secureserver.net/PC/activerecord-create_decorator' 10 | s.files = Dir['lib/**/*'] + ['README.md'] 11 | 12 | s.add_dependency "activerecord", ">= 3.2" 13 | end 14 | -------------------------------------------------------------------------------- /lib/activerecord/abstract_adapter_ext.rb: -------------------------------------------------------------------------------- 1 | module ActiveRecord::ConnectionAdapters::AbstractAdapterExt 2 | def create_table(table_name, options={}, &block) 3 | create_options = ActiveRecord::Base.connection_config[:create_options] 4 | if create_options 5 | current_options = options[:options] 6 | if current_options 7 | options[:options] = "#{current_options} #{create_options}" 8 | else 9 | options[:options] = create_options 10 | end 11 | end 12 | 13 | super 14 | end 15 | end 16 | 17 | # bundle modified behavior with the AbstractAdapter class 18 | ActiveRecord::ConnectionAdapters::AbstractAdapter.include ActiveRecord::ConnectionAdapters::AbstractAdapterExt 19 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 GoDaddy 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ActiveRecord::CreateDecorator 2 | 3 | Modifies table creation done through ActiveRecord to allow you to specify connection-specific table options. Technically you can do this within your migrations by passing along an options hash, but that requires you to introduce adapter-specific logic in those migrations if you want to support different database providers, along with switching to the sql-based schema dumper. With this your migrations remain adapter-agnostic and you can continue to make use of schema.rb. Obviously, this won't help you if you're doing other DB-specific stuff like stored procedures or whatever, but it works great for setting a default row_format in mysql. 4 | 5 | ## Installation 6 | 7 | Add the following to your gemfile. The later the better, to avoid any sort of weird interactions with other things 8 | that might be messing with your connection handling (Apartment, I'm looking at you) 9 | 10 | `gem 'activerecord-create_decorator'` 11 | 12 | ## Usage 13 | 14 | Simply add a create_options attribute within your database.yml related to the specific connection you want to modify, e.g. 15 | 16 | ``` 17 | development: 18 | adapter: mysql2 19 | encoding: utf8mb4 20 | collation: utf8mb4_unicode_ci 21 | reconnect: true 22 | database: my_database 23 | pool: 5 24 | username: someuser 25 | password: somepassword 26 | host: 127.0.0.1 27 | port: 3306 28 | create_options: 'DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC' 29 | ``` 30 | 31 | Any table creates that operate through that connection will have the options specified merged into existing options. 32 | 33 | -------------------------------------------------------------------------------- /spec/lib/activerecord/schema_statements_ext_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | RSpec.describe ActiveRecord::ConnectionAdapters::AbstractAdapterExt do 4 | 5 | let(:table) { 'table_name' } 6 | let(:create_options) { 'base_options' } 7 | let(:current_options) { 'current_options' } 8 | let(:both_options) { 'current_options base_options' } 9 | let(:block) { TestClass.block_was_called } 10 | 11 | class TestClass # mimics AbstractAdapter 12 | include ActiveRecord::ConnectionAdapters::SchemaStatements 13 | include ActiveRecord::ConnectionAdapters::AbstractAdapterExt 14 | 15 | def self.block_was_called 16 | end 17 | end 18 | 19 | before(:each) do 20 | expect(TestClass).to receive(:block_was_called) 21 | expect_any_instance_of(TestClass).to receive(:execute) 22 | allow_any_instance_of(TestClass).to receive_message_chain(:schema_creation, :accept) 23 | allow_any_instance_of(TestClass).to receive(:supports_indexes_in_create?) 24 | allow_any_instance_of(TestClass).to receive(:supports_comments?) 25 | end 26 | 27 | describe '#create_table' do 28 | # any_args is used to bridge differences between ActiveRecord versions 29 | 30 | context 'with create_options' do 31 | before(:each) do 32 | allow(ActiveRecord::Base).to receive(:connection_config).and_return({ create_options: create_options }) 33 | end 34 | 35 | context 'with current_options' do 36 | it 'adds connection config to options arg and forwards to parent' do 37 | expect_any_instance_of(TestClass).to receive(:create_table_definition).with( 38 | table, nil, both_options, any_args).and_call_original 39 | 40 | TestClass.new.create_table(table, { options: current_options }) { block } 41 | end 42 | end 43 | 44 | context 'without current_options' do 45 | it 'sends connection config as option' do 46 | expect_any_instance_of(TestClass).to receive(:create_table_definition).with( 47 | table, nil, create_options, any_args).and_call_original 48 | 49 | TestClass.new.create_table(table) { block } 50 | end 51 | end 52 | end 53 | 54 | context 'without create_options' do 55 | before(:each) do 56 | allow(ActiveRecord::Base).to receive(:connection_config).and_return({}) 57 | end 58 | 59 | context 'with current_options' do 60 | it 'sends just current_options' do 61 | expect_any_instance_of(TestClass).to receive(:create_table_definition).with( 62 | table, nil, current_options, any_args).and_call_original 63 | 64 | TestClass.new.create_table(table, { options: current_options }) { block } 65 | end 66 | end 67 | 68 | context 'without current_options' do 69 | it 'sends no options' do 70 | expect_any_instance_of(TestClass).to receive(:create_table_definition).with( 71 | table, nil, nil, any_args).and_call_original 72 | 73 | TestClass.new.create_table(table) { block } 74 | end 75 | end 76 | end 77 | end 78 | end 79 | --------------------------------------------------------------------------------