【问题标题】:How to Handle ActiveRecord Migrations in a Distributed Gem?如何处理分布式 Gem 中的 ActiveRecord 迁移?
【发布时间】:2013-04-03 07:25:51
【问题描述】:

我正在尝试使用没有 Rails 的 ActiveRecord 将应用程序编写为 gem。

我的问题是如何迁移已经由没有 rake 的用户部署的数据库等。我刚刚分发了一个 schema.rb 文件并从中创建了数据库。但现在我想允许用户更新到新的 gem 并迁移他们的数据库。

我查看过 ActiveRecord::Migrator,但不知道如何使用它。

例如,我如何告诉 ActiveRecord::Migrator 从 current_migration 运行所有迁移?

有人对如何进行此操作或一个好的参考有任何建议吗?

【问题讨论】:

    标签: activerecord gem rails-migrations


    【解决方案1】:

    今天早上在这个新鲜的地方之后,我想出了以下运行良好的方法:

    module Byr
      module Db
    
        class << self
          attr_accessor :config
          attr_accessor :adapter
          attr_accessor :db_name
        end
    
        def self.create_sqlite(config)
          require 'sqlite3'
          config = config.merge('database' => File.join(Byr.db_dir, config['database']))
          ActiveRecord::Base.establish_connection(config)
        end
    
        def self.create_pg(config)
          require 'pg'
          # Connect to the postgres db to create the db
          ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres',
                                                               'schema_search_path' => 'public'))
          begin
            result = ActiveRecord::Base.connection.create_database(config['database'])
          rescue PG::Error, ActiveRecord::StatementInvalid => e
            unless e.message =~ /already exists/
              raise
            end
          end
          true
        end
    
        def self.mysql_creation_options(config)
          @charset   = ENV['CHARSET']   || 'utf8'
          @collation = ENV['COLLATION'] || 'utf8_unicode_ci'
          {:charset => (config['charset'] || @charset), :collation => (config['collation'] || @collation)}
        end
    
        def self.create_mysql(config)
          require 'mysql2'
          error_class = config['adapter'] =~ /mysql2/ ? Mysql2::Error : Mysql::Error
          begin
            ActiveRecord::Base.establish_connection(config.merge('database' => nil))
            ActiveRecord::Base.connection.create_database(config['database'], mysql_creation_options(config))
            ActiveRecord::Base.establish_connection(config)
          rescue error_class => sqlerr
            access_denied_error = 1045
            if sqlerr.errno == access_denied_error
              print "#{sqlerr.error}. \nPlease provide the root password for your mysql installation\n>"
              root_password = $stdin.gets.strip
              grant_statement = "GRANT ALL PRIVILEGES ON #{config['database']}.* " \
              "TO '#{config['username']}'@'localhost' " \
              "IDENTIFIED BY '#{config['password']}' WITH GRANT OPTION;"
              ActiveRecord::Base.establish_connection(config.merge(
                                                                   'database' => nil, 'username' => 'root', 'password' => root_password))
              ActiveRecord::Base.connection.create_database(config['database'], mysql_creation_options(config))
              ActiveRecord::Base.connection.execute grant_statement
              ActiveRecord::Base.establish_connection(config)
            else
              Byr.warn sqlerr.error
              Byr.warn "Couldn't create database for #{config.inspect}, charset: #{config['charset'] || @charset}, collation: #{config['collation'] || @collation}"
              Byr.warn "(if you set the charset manually, make sure you have a matching collation)" if config['charset']
            end
          rescue ActiveRecord::StatementInvalid => e
            ActiveRecord::Base.establish_connection(config)
          end
        end
    
        def self.migrate
          sys_migration_dir = File.join(Byr.install_dir, "db/migrate")
          ActiveRecord::Migration.verbose = true
          ActiveRecord::Migrator.migrate(sys_migration_dir)
        end
    
        def self.connected?
          ActiveRecord::Base.connected? and
            ActiveRecord::Base.connection_config[:adapter] == adapter
        end
    
        def self.disconnect
          ActiveRecord::Base.connection_pool.disconnect!
        end
    
        # Really only for testing
        def self.drop_db
          ActiveRecord::Base.connection.drop_database(Byr.db_config)
        end
      end
    end
    

    然后,通过迁移初始化数据库:

    module Byr
      class << self
        attr_accessor :install_dir
        attr_accessor :db_dir
        attr_accessor :config_dir
        attr_accessor :config_file
        attr_accessor :config
        attr_accessor :db_config
        attr_accessor :adapter
        attr_accessor :database
      def self.create_db
        case db_config['adapter']
        when /postgresql/
          Byr::Db.create_pg(db_config)
        when /sqlite/
          Byr::Db.create_sqlite(db_config)
        when /mysql/
          Byr::Db.create_mysql(db_config)
        else
          raise ByrError "Your config.yml file specifies an unknown database adapter \'#{config['adapter']}\'"
        end
      end
    
      def self.connect_db(reconnect = false)
        unless reconnect
          return true if Byr.connected?
        end
        ActiveRecord::Base.establish_connection(db_config)
      end
    
      def self.migrate
        Byr::Db.migrate
      end
    
      def self.init(connect = true, adapter = nil)
        adapter = canonicalize_adapter(adapter) if adapter
        setup_db_config
        if connect
          create_db and connect_db and migrate
        end
      end
    end
    

    省略了一些不相关的代码部分,但我希望这会有所帮助 别人。

    很多困难的东西来自 rails 中的 rake 任务。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-23
      • 1970-01-01
      • 1970-01-01
      • 2013-08-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多