谷歌搜索后,我仍然无法找到一种成功的方法来覆盖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
不存在。
我做错了什么?谢谢。
答案 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