覆盖Rails 4和SQLite中的主键列

时间:2014-07-22 10:04:14

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

谷歌搜索后,我仍然无法找到一种成功的方法来覆盖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不存在。

我做错了什么?谢谢。

1 个答案:

答案 0 :(得分:2)

好的,我已经为自己找到了解决方案:独立执行每个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