Pergunta

Eu estou usando JRuby e trilhos 2.2.2. Meu problema é que eu tenho uma migração que não está sendo corretamente escrita ao esquema de banco de dados.

Aqui está a minha migração:

class CreateNotes < ActiveRecord::Migration
  def self.up
    create_table(:notes, :options => 'ENGINE=MyISAM') do |t|
      t.string :title
      t.text :body

      t.timestamps
    end

    execute "alter table notes ADD FULLTEXT(title, body)"

end

Aqui está o que ela produz sobre em schema.rb

create_table "notes", :force => true do |t|
  t.string   "title"
  t.text     "body"
  t.datetime "created_at"
  t.datetime "updated_at"
end

add_index "notes", ["title", "body"], :name => "title"

Eu tenho duas perguntas:

  • Como faço para obter 'ENGINE=MyISAM' no esquema?
  • Por que a executar declaração add_index "notes", ["title", "body"], :name => "title" tornar-se? e como faço para forçar migrações para deixá-lo como uma instrução de execução?

Graças a Christian Lescuyer para a resposta. No entanto, quando eu tentei isso nada mudou. Eu uncommented o config.active_record ... linha, mas, meu esquema não mudou. Eu tentei isso em jruby e em ruby ??1.8.6 com trilhos 2.2.2 e trilhos de borda e não há alterações no esquema. Alguém pode me dizer o que estou fazendo de errado?

Foi útil?

Solução

Como eu uso restrições de chave estrangeira, eu uso o formato SQL para migrações. Em environment.rb :

# Use SQL instead of Active Record's schema dumper when creating the test database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
# like if you have constraints or database-specific column types
config.active_record.schema_format = :sql

Outras dicas

Eu esperava muito de ver uma nova ficheiro.sql aparecem depois de um "rake db: migrar", uma vez que eu definir

config.active_record.schema_format = :sql

no config / environment.rb.

Aparentemente, isso não é assim que funciona, no entanto. Eu tenho que fazer isso explicitamente para obter um db / [desenvolvimento | teste | produção] arquivo _structure.sql:

rake db:structure:dump

Apenas uma atualização para aqueles on Rails 3 (beta 4, atualmente) - A solução da Christian ainda está correto, apenas o lugar correto para colocar a linha está em config/application.rb, no âmbito da classe Application que deve ser definido em um módulo nomeado após seu projeto Rails.

cristão é certo.

fazer

config.active_record.schema_format =: sql

em environment.rb

mas então você tem que usar um formato de despejo de esquema e arquivo local diferente. tente fazer a migração e à procura de "schema.sql" em vez de scehema.rb

a razão para tudo isso é que o ponto do arquivo de esquema é uma inespecífica banco de dados (obras para todos os tipos de bancos de dados) arquivo. Então, quando você usar recursos que só funcionam em mysql através de um unsupoorted executar declaração, eles não podem ser shoehorned no schema.rb

Para usar a variante SQL para testar (em vez de schema.rb), você vai precisar usar

rake db: test: clone_structure

Nossos usos esquema UUIDs (gem UUID) e também Red Hill on Rails (RHoR) nice FK plug-in. Infelizmente, os FKs exigem PKs que só podem ser adicionados usando executado no migrações.

É bem conhecido que estes executa não fazê-lo ao schema.rb; no entanto, foi mais difícil de encontrar a alternativa ancinho para db: test:. preparar para aplicativos que não podem usar schema.rb

Os seguintes resolve monkeypatch tanto a questão índice FULLTEXT e opção de motor DB para o seu dumper esquema (Rails 3.2). Você pode colocá-lo em config/initializers/ (por exemplo schema_dumper_monkeypatch.rb):

module ActiveRecord
  class SchemaDumper
    def table(table, stream)
      columns = @connection.columns(table)
      begin
        tbl = StringIO.new

        # first dump primary key column
        if @connection.respond_to?(:pk_and_sequence_for)
          pk, _ = @connection.pk_and_sequence_for(table)
        elsif @connection.respond_to?(:primary_key)
          pk = @connection.primary_key(table)
        end

        tbl.print "  create_table #{remove_prefix_and_suffix(table).inspect}"
        if columns.detect { |c| c.name == pk }
          if pk != 'id'
            tbl.print %Q(, :primary_key => "#{pk}")
          end
        else
          tbl.print ", :id => false"
        end
        tbl.print ", :force => true"

        # Add table engine
        res = @connection.execute "SHOW TABLE STATUS LIKE '#{table}'"
        engine = res.first[res.fields.index("Engine")] rescue nil
        tbl.print ", :options => 'ENGINE=#{engine}'" if engine
        res = nil # Free the result        

        tbl.puts " do |t|"

        # then dump all non-primary key columns
        column_specs = columns.map do |column|
          raise StandardError, "Unknown type '#{column.sql_type}' for column '#{column.name}'" if @types[column.type].nil?
          next if column.name == pk
          spec = {}
          spec[:name]      = column.name.inspect

          # AR has an optimization which handles zero-scale decimals as integers. This
          # code ensures that the dumper still dumps the column as a decimal.
          spec[:type]      = if column.type == :integer && [/^numeric/, /^decimal/].any? { |e| e.match(column.sql_type) }
                               'decimal'
                             else
                               column.type.to_s
                             end
          spec[:limit]     = column.limit.inspect if column.limit != @types[column.type][:limit] && spec[:type] != 'decimal'
          spec[:precision] = column.precision.inspect if column.precision
          spec[:scale]     = column.scale.inspect if column.scale
          spec[:null]      = 'false' unless column.null
          spec[:default]   = default_string(column.default) if column.has_default?
          (spec.keys - [:name, :type]).each{ |k| spec[k].insert(0, "#{k.inspect} => ")}
          spec
        end.compact

        # find all migration keys used in this table
        keys = [:name, :limit, :precision, :scale, :default, :null] & column_specs.map{ |k| k.keys }.flatten

        # figure out the lengths for each column based on above keys
        lengths = keys.map{ |key| column_specs.map{ |spec| spec[key] ? spec[key].length + 2 : 0 }.max }

        # the string we're going to sprintf our values against, with standardized column widths
        format_string = lengths.map{ |len| "%-#{len}s" }

        # find the max length for the 'type' column, which is special
        type_length = column_specs.map{ |column| column[:type].length }.max

        # add column type definition to our format string
        format_string.unshift "    t.%-#{type_length}s "

        format_string *= ''

        column_specs.each do |colspec|
          values = keys.zip(lengths).map{ |key, len| colspec.key?(key) ? colspec[key] + ", " : " " * len }
          values.unshift colspec[:type]
          tbl.print((format_string % values).gsub(/,\s*$/, ''))
          tbl.puts
        end

        tbl.puts "  end"
        tbl.puts

        indexes(table, tbl)

        tbl.rewind
        stream.print tbl.read
      rescue => e
        stream.puts "# Could not dump table #{table.inspect} because of following #{e.class}"
        stream.puts "#   #{e.message}"
        stream.puts
      end

      stream
    end    

    def indexes(table, stream)
      if (indexes = @connection.indexes(table)).any?
        add_index_statements = indexes.map do |index|

          if index.name =~ /fulltext/i
            "  execute \"CREATE FULLTEXT INDEX #{index.name} ON #{index.table} (#{index.columns.join(',')})\""
          elsif index.name =~ /spatial/i
            "  execute \"CREATE SPATIAL INDEX #{index.name} ON #{index.table} (#{index.columns.join(',')})\""
          else
            statement_parts = [
              ('add_index ' + remove_prefix_and_suffix(index.table).inspect),
              index.columns.inspect,
              (':name => ' + index.name.inspect),
            ]
            statement_parts << ':unique => true' if index.unique

            index_lengths = (index.lengths || []).compact
            statement_parts << (':length => ' + Hash[index.columns.zip(index.lengths)].inspect) unless index_lengths.empty?

            index_orders = (index.orders || {})
            statement_parts << (':order => ' + index.orders.inspect) unless index_orders.empty?

            '  ' + statement_parts.join(', ')
          end
        end

        stream.puts add_index_statements.sort.join("\n")
        stream.puts
      end
    end
  end
end
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top