如何进行数据库迁移创建具有特定属性的表?

时间:2012-12-31 13:53:42

标签: ruby-on-rails activerecord sqlite migration

我正在尝试学习rails,我遇到了一些问题。

我有一个旧的sqlite3数据库,它有一个Accounts表,我之前用一些GUI程序制作。我想看看我是否可以通过数据库迁移重新创建该表。

以下是我之前的描述(我的目标):

-- desired
CREATE TABLE "accounts" (
  "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL DEFAULT (0),
  "username" TEXT NOT NULL COLLATE NOCASE,
  "password_hash" BLOB NOT NULL,
  "creation_time" INTEGER NOT NULL DEFAULT(strftime('%s', 'now')),
  "expiration_time" INTEGER NOT NULL DEFAULT(strftime('%s', 'now') + 2592000)
)

我当前的迁移代码无法正常运行。我在某处读到了我可以使用:options来指定ActiveRecord无法封装的内容,但我可能做错了。当我使用:default => Time.now.to_i时,它只是硬编码了一些默认值;当我使用:default => "strftime('%s', 'now')"时,它根本不起作用。

class CreateAccounts < ActiveRecord::Migration
  def change
    create_table :accounts do |t|
      t.column 'username', :text, :null => false, :options => 'COLLATE NOCASE'
      t.column 'password_hash', :binary, :null => false
      t.column 'creation_time', :integer, :null => false, :options => "DEFAULT(strftime('%s', 'now'))"
      t.column 'expiration_time', :integer, :null => false, :options => "DEFAULT(strftime('%s', 'now') + 2592000)"
    end
  end
end

我最终得到了下表。看起来所有:option值都被忽略了。

-- what i actually get
CREATE TABLE "accounts" (
  "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
  "username" text NOT NULL,
  "password_hash" blob NOT NULL,
  "creation_time" integer NOT NULL,
  "expiration_time" integer NOT NULL
)

创建列时如何指定SQL的位数?任何帮助都将非常感激。

3 个答案:

答案 0 :(得分:3)

您可以做的最简单的事情就是执行原始SQL来定义表。这看起来像是:

class CreateAccounts < ActiveRecord::Migration
  def up
    execute <<-SQL
    CREATE TABLE "accounts" (
      "id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL DEFAULT (0),
      "username" TEXT NOT NULL COLLATE NOCASE,
      "password_hash" BLOB NOT NULL,
      "creation_time" INTEGER NOT NULL DEFAULT(strftime('%s', 'now')),
      "expiration_time" INTEGER NOT NULL DEFAULT(strftime('%s', 'now') + 2592000)
    )
    SQL
  end

  def down
    remove_table :accounts
  end
end

通过这种方式,您将获得与之前相同的表格。我不完全确定你是否可以用当前的迁移DSL表达这样的表定义。你应该能够验证它。如果您使用上述原始SQL进行迁移,则可以运行rake db:migrate。这应该生成一个新的db/schema.rb。然后,您可以打开该文件并搜索帐户表并查看定义。如果包含所有内容,您可以将该定义复制回迁移。

答案 1 :(得分:1)

默认值为:

t.column :creation_time, :integer, :null => false, :default => "strftime('%s', 'now'))"

collat​​e和nocase不能通过ruby完成,但你可以使用execute方法来运行raw sql:

execute "ALTER TABLE accounts ADD COLUMN username TEXT NOT NULL COLLATE NOCASE AFTER id

或者,您可以简单地将排序规则替换为:

class Account < ActiveRecord::Base
  def username=(username)
    write_attribute :username, username.downcase
  end
end

答案 2 :(得分:1)

您的迁移看起来很不错。

由于你确实想学习Rails,我会坚持使用它并尝试解决具体问题。

对于rails,对于创建和更新的日期/时间戳,您要做的是创建名为updated_at和created_at(或每个_on)的字段,然后当rails使用活动记录进行数据库表行更新时,它将适当地更新这些字段并自动(或自动地,如某些人所说)。

这是Rails的基本租户 - 约定优于配置&gt;选择正确的名称和限制,它将为你做“繁重”。

你的问题既使用默认的现在但是硬编码在反思中有意义,但上面的内容将解决它