ruby-on-rails - sirve - ruby on rails modelos
Problema de creación del esquema de Rails (6)
Estoy usando Jruby y Rails 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.
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 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 obtengo
''ENGINE=MyISAM''
en el esquema? - ¿Por qué mi sentencia 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?
Como utilizo 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
Christian tiene razón
hacer
config.active_record.schema_format =: sql
en environment.rb
pero luego debe usar un formato de volcado de esquema y una ubicación de archivo diferentes. intente hacer su migración y busque "schema.sql" en lugar de scehema.rb
El motivo de todo esto es que el punto 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 agrupada, no pueden ser calzados en schema.rb
Yo también esperaba ver un nuevo archivo .sql después de un "rake db: migrate", una vez que configuré
config.active_record.schema_format = :sql
en config / environment.rb.
Aparentemente, no es así como funciona, sin embargo. Debo hacer esto explícitamente para obtener un archivo db / [development | test | production] _structure.sql:
rake db:structure:dump
Para utilizar la variante SQL para probar (en lugar de schema.rb), deberá usar
rake db: test: clone_structure
Nuestro esquema usa UUID (uuid gem) y también el agradable FK plug-in de Red Hill on Rails (RHoR). 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.
Solo una actualización para aquellos en Rails 3 (beta 4, actualmente) - La solución de Christian sigue siendo correcta, solo el lugar correcto para poner la línea es en config/application.rb
, bajo el alcance de la clase Application
, que debe definirse en una módulo nombrado después de su proyecto Rails.
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). Puedes ponerlo en config/initializers/
(ej. 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