Rails Schema creation problem

前端 未结 6 1906
悲哀的现实
悲哀的现实 2021-02-01 09:52

I am using Jruby and rails 2.2.2. My problem is I have a migration that is not being correctly written to the database schema.

Here is my migration:

c         


        
相关标签:
6条回答
  • 2021-02-01 10:08

    As I use foreign key constraints, I use the SQL format for migrations. 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
    
    0 讨论(0)
  • 2021-02-01 10:16

    Just an update for those on Rails 3 (beta 4, currently) - Christian's solution is still correct, only the correct place to put the line is in config/application.rb, under the scope of the Application class which should be defined in a module named after your Rails project.

    0 讨论(0)
  • 2021-02-01 10:16

    christian is right.

    do

    config.active_record.schema_format = :sql

    in environment.rb

    but then you have to use a different schema dump format and file location. try doing your migration and looking for "schema.sql" instead of scehema.rb

    the reason for all of this is that the point of the scheme file is a database unspecific (works for all types of databases) file. so when you use features which only work on mysql through an unsupoorted execute statement, they can't be shoehorned in to schema.rb

    0 讨论(0)
  • 2021-02-01 10:18

    I too expected to see a new .sql file appear after a "rake db:migrate", once I set

    config.active_record.schema_format = :sql
    

    in config/environment.rb.

    Apparently that's not how it works, however. I have to do this explicitly to get a db/[development|test|production]_structure.sql file:

    rake db:structure:dump
    
    0 讨论(0)
  • 2021-02-01 10:22

    The following monkeypatch solves both the FULLTEXT index issue and DB engine option for your schema dumper (Rails 3.2). You can put it in config/initializers/ (e.g. 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
    
    0 讨论(0)
  • 2021-02-01 10:34

    To use the SQL variant for testing (instead of schema.rb), you'll need to use

    rake db:test:clone_structure

    Our schema uses UUIDs (uuid gem) and also Red Hill on Rails (RHoR) nice FK plug-in. Unfortunately, the FKs require PKs that can only be added using EXECUTES in the migrations.

    It's well known that these executes do not make it to the schema.rb; however, it was harder to find the rake alternative to db:test:prepare for apps that cannot use schema.rb.

    0 讨论(0)
提交回复
热议问题