2008-12-20 21 views
10

Estoy usando Jruby y los carriles 2.2.2. Mi problema es que tengo una migración que no se está escribiendo correctamente en el esquema de la base de datos.Problema de creación del esquema de Rails

Aquí es mi migración:

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 

Esto es lo que produce en schema.rb en

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" 

tengo dos preguntas:

  • ¿Cómo llego a 'ENGINE=MyISAM' el esquema?
  • ¿Por qué mi declaración de ejecución se convirtió en add_index "notes", ["title", "body"], :name => "title"? y ¿cómo obligo a las migraciones a dejarlo como una instrucción de ejecución?

Gracias a Christian Lescuyer por la respuesta. Sin embargo, cuando probé esto, nada cambió. Descomenté la línea config.active_record ... pero mi esquema no ha cambiado. He intentado esto en jruby y en ruby ​​1.8.6 con rieles 2.2.2 y rieles laterales y no hay cambios en el esquema. ¿Alguien puede decirme qué estoy haciendo mal?

+0

¿Ha borrado schema.rb? Debería obtener un archivo .sql en su lugar, pero creo que el viejo schema.rb aún se encuentra. –

Respuesta

8

Como uso restricciones de clave externa, utilizo el formato SQL para migraciones. En 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 
1

cristiana es correcta.

hacer

config.active_record.schema_format =: sql

en environment.rb

pero luego se va a utilizar un formato de volcado de archivos de esquema y ubicación diferente. intente realizar su migración y buscar "schema.sql" en lugar de scehema.rb

El motivo de todo esto es que el objetivo del archivo de esquema es una base de datos no específica (funciona para todos los tipos de bases de datos). por lo tanto, cuando utiliza funciones que solo funcionan en mysql a través de una sentencia de ejecución no organizada, no pueden ser calzados en schema.rb

10

Yo también esperaba ver un nuevo archivo .sql después de un "rake db: migrate" Una vez que configuro

config.active_record.schema_format = :sql 

en config/environment.rb.

Aparentemente, no es así como funciona. Tengo que hacer esto de forma explícita para obtener una db/[desarrollo | prueba | producción] archivo _structure.sql:

rake db:structure:dump 
+0

Hacer un rake db: test: prepare hará automáticamente un db: structure: dump de la base de datos de desarrollo y luego un db: structure: cargar en la base de datos de prueba cuando el schema_format está configurado a: sql –

1

Para utilizar la variante de SQL para las pruebas (en lugar de schema.rb), usted necesitará utilizar

rake db: test: clone_structure

Nuestro esquema utiliza UUID (UUID) de la gema y también Red Hill on Rails (Rhor) FK buen complemento. Desafortunadamente, los FK requieren PK que solo se pueden agregar usando EJECUCIONES en las migraciones.

Es bien sabido que estos ejecutables no llegan a schema.rb; sin embargo, fue más difícil encontrar la alternativa de rake a db: test: prepararse para aplicaciones que no pueden usar schema.rb.

6

Solo una actualización para los usuarios de Rails 3 (beta 4, actualmente) - La solución de Christian sigue siendo correcta, solo el lugar correcto para poner la línea es config/application.rb, bajo el alcance de la clase Application que debe definirse de módulo nombrado después de su proyecto Rails.

+1

Cabello DHH agradable en tu icono – gtd

1

El siguiente monkeypatch resuelve tanto el problema del índice FULLTEXT como la opción del motor de DB para su descargador de esquemas (Rails 3.2). Se puede poner en config/initializers/ (por ejemplo 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 
Cuestiones relacionadas