【问题标题】:Overriding primary key column in Rails 4 and SQLite在 Rails 4 和 SQLite 中覆盖主键列
【发布时间】:2014-09-13 02:20:53
【问题描述】:

谷歌搜索后,我仍然无法找到一种成功的方法来覆盖 Rails 在使用 SQLite 时添加的主键。到目前为止,我有以下基本迁移:

class CreateRequests < ActiveRecord::Migration
    def change
        create_table :requests, id: false do |t|
            t.string :id
            t.string :name
        end    
    end
end

上面的代码告诉 Rails 不要添加默认的id 主键。相反,我想使用字符串类型的id。

问题出在SQLite的ALTER命令的限制,创建表后不能添加主键。因此,我尝试了这种解决方法:

class CreateRequests < ActiveRecord::Migration
    def change
        create_table :requests, id: false do |t|
            t.string :id
            t.string :name
        end    

        adapter_type = connection.adapter_name.downcase.to_sym    
        case adapter_type
            when :postgresql
                # TODO
            when :sqlite        
                execute <<-SQL          
                    DROP TABLE requests;
                    CREATE TABLE requests (id TEXT NOT NULL PRIMARY KEY, name TEXT);
                SQL
            else
                raise NotImplementedError, "Unknown adapter type '#{adapter_type}'"
            end

    end
end

运行rake db:migrate 后,我得到了这个输出:

== 20140722082104 CreateRequests: migrating ===================================
-- create_table(:requests, {:id=>false})
   -> 0.0010s
-- execute("          DROP TABLE requests;\n          CREATE TABLE requests (id
     TEXT NOT NULL PRIMARY KEY, name TEXT);\n")
   -> 0.0010s
== 20140722082104 CreateRequests: migrated (0.0030s) ==========================

所以,看起来一切正常,但是当我使用 SQLite 管理程序检查数据库文件时,表 requests 不存在。

我做错了什么?谢谢。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 sqlite rails-migrations


    【解决方案1】:

    好的,我自己找到了解决方案:独立执行每个 SQL 语句:

    execute "DROP TABLE requests;"
    execute "CREATE TABLE requests (id TEXT NOT NULL PRIMARY KEY, name TEXT);"
    

    编辑

    防止手动创建表的更优雅的解决方案,特别是当表有很多列并且我们希望与 ActiveRecord 的 create_table 方法的调用保持同步时:

    #Get from SQLite's master table the SQL statement that creates the table, 
    #and that was initially generated by Rails
    sql = select_value("SELECT sql FROM sqlite_master WHERE type='table' AND name='requests'")
    
    #Only replace the definition of the 'id' column by adding the PRIMARY KEY
    #constraint
    sql.gsub!(/"id" [^,]+/, '"id" VARCHAR(255) NOT NULL PRIMARY KEY')     
    
    #Delete the original table            
    drop_table :requests 
    
    #Create the table again
    execute sql
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-29
      • 2016-09-09
      • 1970-01-01
      • 2021-08-10
      相关资源
      最近更新 更多