Rails Schema Schaffung Problem
-
23-08-2019 - |
Frage
Ich bin mit JRuby und Schienen 2.2.2. Mein Problem ist, ich habe eine Migration, die nicht auf das Datenbankschema korrekt geschrieben werden.
Hier ist meine Migration:
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
Hier ist, was es produziert auf in 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"
Ich habe zwei Fragen:
- Wie kann ich
'ENGINE=MyISAM'
in das Schema bekommen? - Warum wird ausführen Statement
add_index "notes", ["title", "body"], :name => "title"
? und wie kann ich Migrationen zwingen zu lassen, wie eine Ausführungsanweisung?
Dank Christian Lescuyer für die Antwort. Allerdings, wenn ich versuchte, diese nichts geändert. Ich unkommentiert die config.active_record ... Linie aber, mein Schema nicht geändert hat. Ich habe dies in jruby versucht und auf Rubin 1.8.6 mit Schienen 2.2.2 und Kantenschienen und es gibt keine Änderungen im Schema. Kann mir jemand sagen, was ich falsch mache?
Lösung
Als ich für Fremdschlüssel verwenden, verwende ich das SQL-Format für Migrationen. In 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
Andere Tipps
Auch ich erwartete eine neue SQL-Datei erscheint nach einem sehen „rake db: wandern“, wenn ich gesetzt
config.active_record.schema_format = :sql
in config / environment.rb.
Das ist offenbar nicht, wie es funktioniert, aber. Ich habe dies zu tun explizit eine db / [Entwicklung | Test | Produktion] zu erhalten _structure.sql Datei:
rake db:structure:dump
Nur ein Update für die auf Rails 3 (beta 4, zur Zeit) - Christian-Lösung ist nach wie vor richtig, nur der richtige Ort, um die Linie zu setzen ist in config/application.rb
, unter dem Anwendungsbereich der Application
Klasse, die in einem Modul definiert werden soll benannt nach dem Rails-Projekt.
christian richtig ist.
do
config.active_record.schema_format = SQL
in environment.rb
aber dann müssen Sie ein anderes Schema Dump-Format und Speicherort der Datei verwenden. versuchen Sie die Migration und die Suche nach „schema.sql“ statt scehema.rb tun
der Grund für all dies ist, dass der Punkt der Schemadatei eine Datenbank unspezifisch Datei (für alle Arten von Datenbanken funktioniert). so, wenn Sie Funktionen, die nur auf MySQL arbeiten durch eine unsupoorted Anweisung ausführen, können sie nicht in bugsiert werden, um schema.rb
Um die SQL-Variante zum Testen (statt schema.rb) zu verwenden, werden Sie verwenden müssen, um
rake db: test: clone_structure
Unser Schema verwendet UUID (UUID gem) und auch Red Hill on Rails (Rhor) nice FK-Plug-in. Unglücklicherweise erfordern die FKs PKs, die nur mit FÜHRT in den Migrationen hinzugefügt werden können.
Es ist bekannt, dass diese ausführt zum schema.rb macht es nicht; war es jedoch schwieriger, die Harke Alternative zu finden auf dem db: test:. Vorbereitung für Anwendungen, die nicht schema.rb verwenden
Das folgende monkeypatch löst sowohl den Volltextindex Ausgabe und DB-Engine-Option für Ihr Schema dumper (Rails 3.2). Sie können es in config/initializers/
setzen (z 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