MySQL double to PostgreSQL双精度工作,但schema.rb转储中不存在默认列值

时间:2014-12-24 08:43:40

标签: ruby-on-rails postgresql rails-activerecord

我在一个Rails应用程序中将MySQL数据库转换为PostgreSQL,并且在PostgreSQL中将MySQL double列转换为double precision列。

问题是,即使PostgreSQL结构的此列具有默认值“0 :: double precision”,rake db:schema:dump也不会添加此默认值。

因此,在创建模型实例时,默认值不会自动分配,而是其值为nil

现在,我正在使用Rails 4.1.6,这是因为列类型未列出here(AFAIK)。奇怪(对我来说)是为什么还没有添加。

这里推荐的方法是什么?在PostgreSQL中更改列类型?

\d payments内的psql说:

                                       Table "public.payments"
     Column     |            Type             |                       Modifiers                       
----------------+-----------------------------+-------------------------------------------------------
 id             | integer                     | not null default nextval('payments_id_seq'::regclass)
 credit_card_id | integer                     | not null default 0
 order_id       | integer                     | not null default 0
 amount         | double precision            | not null default 0::double precision
 created_at     | timestamp without time zone | not null
 updated_at     | timestamp without time zone | not null
 authorization  | character varying(510)      | default NULL::character varying
Indexes:
    "payments_pkey" PRIMARY KEY, btree (id)
    "credit_card_id" btree (credit_card_id)
    "purchase_order_id_1" btree (order_id)

schema.rb的相应部分说:

create_table "payments", force: true do |t|
  t.integer  "credit_card_id",             default: 0, null: false
  t.integer  "order_id",                   default: 0, null: false
  t.float    "amount",                                 null: false
  t.datetime "created_at",                             null: false
  t.datetime "updated_at",                             null: false
  t.string   "authorization",  limit: 510
end

1 个答案:

答案 0 :(得分:1)

我认为你在ActiveRecord中的extract_value_from_default问题是正确的; AR倾向于忽略它不理解的数据库中的任何内容,并且它不理解::double precision定义中的amount强制转换,因此AR假定没有默认值。

用于将MySQL模式和数据库转换为PostgreSQL的工具也是有问题的。不需要类型转换,PostgreSQL可以将整数转换为双精度,只需:

amount double precision default 0

就足够了。如果您想在默认情况下使用某种类型的提醒,那么您可以使用:

amount double precision default 0.0

AR应该了解其中任何一个。

最简单的解决方案是修复数据库中的默认值并删除类型转换。落后AR的后面并做一个手动的ALTER TABLE就足够了。从psql开始,您可以说:

alter table payments alter column amount set default 0;

或迁移内部:

def up
  connection.execute('alter table payments alter column amount set default 0')
end

之后,您的db:schema:dump应该包含新的默认值,而新创建的Payment应该包含零金额。


另外,您可能希望在数据库中切换到numeric类型(AR调用此t.decimal)。使用浮动点赚钱很少结束。