2008-12-20 28 views
10

Tôi đang sử dụng Jruby và đường ray 2.2.2. Vấn đề của tôi là tôi có một di chuyển không được viết chính xác vào lược đồ cơ sở dữ liệu.Vấn đề tạo lược đồ Rails

Đây là di cư của tôi:

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 

Đây là những gì nó tạo ra trong 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" 

Tôi có hai câu hỏi:

  • Làm thế nào để tôi nhận được 'ENGINE=MyISAM' vào lược đồ?
  • Tại sao tuyên bố thực thi của tôi trở thành add_index "notes", ["title", "body"], :name => "title"? và làm cách nào để buộc di chuyển rời khỏi nó dưới dạng tuyên bố thực thi?

Cảm ơn Christian Lescuyer đã trả lời. Tuy nhiên, khi tôi cố gắng này không có gì thay đổi. Tôi uncommented dòng config.active_record ... nhưng, lược đồ của tôi đã không thay đổi. Tôi đã thử điều này trong jruby và trên ruby ​​1.8.6 với đường ray 2.2.2 và đường ray cạnh và không có thay đổi trong lược đồ. Ai có thể cho tôi biết tôi đang làm gì sai?

+0

Bạn có xóa schema.rb không? Bạn sẽ nhận được một tập tin .sql thay vào đó, nhưng tôi nghĩ rằng schema.rb cũ vẫn nằm xung quanh. –

Trả lời

8

Khi tôi sử dụng các ràng buộc khóa ngoài, tôi sử dụng định dạng SQL để di chuyển. Trong 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

christian là đúng.

làm

config.active_record.schema_format =: sql

trong environment.rb

nhưng sau đó bạn phải sử dụng một định dạng schema bãi và tập tin vị trí khác nhau. hãy thử thực hiện di chuyển của bạn và tìm kiếm "schema.sql" thay vì scehema.rb

lý do cho tất cả điều này là điểm của tệp lược đồ là tệp cơ sở dữ liệu không xác định (hoạt động cho tất cả các loại cơ sở dữ liệu). do đó, khi bạn sử dụng các tính năng chỉ hoạt động trên mysql thông qua một câu lệnh thực thi chưa được phân loại, chúng không thể được shoehorned vào schema.rb

10

Tôi cũng mong đợi sẽ thấy tệp .sql mới xuất hiện sau khi "rake db: migrate" , sau khi tôi đặt

config.active_record.schema_format = :sql 

trong config/environment.rb.

Dường như đó không phải là cách hoạt động của nó. Tôi phải làm điều này một cách rõ ràng để có được một db/[phát triển | nghiệm | sản xuất] _structure.sql file:

rake db:structure:dump 
+0

Thực hiện db rake: test: chuẩn bị sẽ tự động thực hiện db: structure: dump từ cơ sở dữ liệu phát triển và sau đó là db: structure: tải vào cơ sở dữ liệu kiểm tra khi schema_format được đặt thành: sql –

1

Để sử dụng biến thể SQL để thử nghiệm (thay vì schema.rb), bạn sẽ cần phải sử dụng

rake db: test: clone_structure

schema chúng tôi sử dụng UUIDs (uuid đá quý) và cũng Red Hill on Rails (RHoR) đẹp FK plug-in. Thật không may, các FK yêu cầu PK chỉ có thể được thêm bằng cách sử dụng EXECUTES trong di chuyển.

Được biết, các thực thi này không được đưa vào schema.rb; tuy nhiên, khó tìm ra phương án thay thế cho db: test: chuẩn bị cho các ứng dụng không thể sử dụng schema.rb.

6

Chỉ cập nhật cho những người trên Rails 3 (beta 4, hiện tại) - Giải pháp của Christian vẫn chính xác, chỉ đúng địa điểm để đặt dòng là config/application.rb, trong phạm vi của lớp Application cần được xác định trong mô-đun được đặt tên sau dự án Rails của bạn.

+1

Tóc DHH đẹp trong biểu tượng của bạn – gtd

1

Khỉpatch sau giải quyết cả vấn đề chỉ mục FULLTEXT và tùy chọn công cụ DB cho dumper lược đồ của bạn (Rails 3.2). Bạn có thể đặt nó trong config/initializers/ (ví dụ: 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 
Các vấn đề liên quan