Carriles problema de la creación de esquemas
-
23-08-2019 - |
Pregunta
Estoy utilizando jruby y carriles 2.2.2. Mi problema es que tengo una migración que no está siendo escrito correctamente en el esquema de base de datos.
Aquí está 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 en 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"
Tengo dos preguntas:
- ¿Cómo consigo
'ENGINE=MyISAM'
en el esquema? -
add_index "notes", ["title", "body"], :name => "title"
¿Por qué la instrucción de ejecución convertirse? y ¿Cómo fuerzo migraciones a dejarlo como una instrucción de ejecución?
Gracias a Christian Lescuyer por la respuesta. Sin embargo, cuando he intentado esto nada cambió. Yo sin comentar la línea de config.active_record ... pero, mi esquema no ha cambiado. He intentado esto en jruby y el rubí 1.8.6 2.2.2 con los carriles y canales del borde y no hay cambios en el esquema. Alguien puede decirme lo que estoy haciendo mal?
Solución
Como utilizo restricciones de clave externa, utilizo el formato de SQL para las 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
Otros consejos
Yo también esperaba ver un nuevo archivo .sql aparece después de un "rake db: migrate", una vez que me puse
config.active_record.schema_format = :sql
en config / environment.rb.
Al parecer no es así como funciona, sin embargo. Tengo que hacer esto de forma explícita para obtener una db / [desarrollo | prueba | producción] archivo _structure.sql:
rake db:structure:dump
Apenas una actualización para aquellos en los carriles 3 (beta 4, en la actualidad) - solución de Christian sigue siendo correcta, sólo el lugar correcto para poner la línea está en config/application.rb
, en el ámbito de la clase Application
que debería definirse en un módulo el nombre de su proyecto Rails.
Christian es correcto.
DO
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. trate de hacer la migración y en busca de "schema.sql" en lugar de scehema.rb
la razón de todo esto es que el punto del archivo de esquema es una base de datos inespecíficos (funciona para todos los tipos de bases de datos) del archivo. por lo que cuando se utilizan las funciones que sólo funcionan en MySQL a través de un comunicado unsupoorted ejecutar, no pueden ser shoehorned a schema.rb
Para utilizar la variante de SQL para probar (en lugar de schema.rb), tendrá que 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. Por desgracia, los FKs requieren PK que sólo pueden ser añadidos usando ejecuta en las migraciones.
Es bien sabido que estos se ejecuta no lo hacen a la schema.rb; sin embargo, era más difícil encontrar la alternativa rake db: test:. prepararse para aplicaciones que no pueden utilizar schema.rb
La siguiente monkeypatch resuelve tanto el problema índice FULLTEXT y la opción de motor de base de datos para su dumper esquema (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