ActiveRecord :: create返回ID = 0的记录

时间:2014-04-17 21:17:49

标签: ruby-on-rails ruby rspec tdd factory-bot

在使用Rails创建对象时遇到问题(在尝试使用FactoryGirl创建实例时注意到它,返回的模型具有id=0,即使它已正确保留并具有正确的ID在DB。其他工厂工作正常,这个似乎没有什么不同。值得注意的是,模型由DB视图支持而不是实际的表,但具有相同“条件”的其他模型正常工作。任何想法?

我的模特是:

class Property::Openhouse < ActiveRecord::Base
  self.table_name  = 'property_open_houses_view'
  self.primary_key = 'id'


  belongs_to :property, :inverse_of => :openhouses
  attr_protected #allow access to all params

  # [SNIP]
end

工厂:

FactoryGirl.define do
  factory :open_house, class: 'Property::Openhouse' do
    property
    mls_system { property.mls_system }
    mls_num { property.mls_num }
    event_date 1.week.from_now
    start_time "10:00AM"
    end_time "6:00PM"
  end
end

IRB(或测试)会发生什么:

development (main):0 > Property::Openhouse.count
   (0.5ms)  SELECT COUNT(*) FROM `property_open_houses_view`
=> 5
development (main):0 > oh = FactoryGirl.create :open_house
=> #<Property::Openhouse id: 0, property_id: 8, mls_num: "V123460", mls_system: :abcdef, event_date: "2014-04-24 19:57:27", start_time: "10:00AM", end_time: "6:00PM", remarks: nil, created_at: "2014-04-17 21:05:15", updated_at: "2014-04-17 21:05:15", open_house_type: nil, most_recent_import_id: nil, expired_at: nil>
development (main):0 > oh.persisted?
=> true
development (main):0 > oh.id
=> 0
development (main):0 > Property::Openhouse.last
  Property::Openhouse Load (0.3ms)  SELECT `property_open_houses_view`.* FROM `property_open_houses_view` ORDER BY `property_open_houses_view`.`id` DESC LIMIT 1
=> #<Property::Openhouse id: 6, property_id: 8, mls_num: "V123460", mls_system: "abcdef", event_date: "2014-04-24 19:57:27", start_time: "10:00AM", end_time: "6:00PM", remarks: nil, created_at: "2014-04-17 21:05:15", updated_at: "2014-04-17 21:05:15", open_house_type: nil, most_recent_import_id: nil, expired_at: nil>
development (main):0 > Property::Openhouse.count
   (0.5ms)  SELECT COUNT(*) FROM `property_open_houses_view`
=> 6 

有什么想法吗?

UPDATE :我使用的是MySQL,视图由单个表支持

CREATE VIEW property_open_houses_view AS
SELECT

`id`,
`property_id`,
`mls_num`,
`event_date`,
`start_time`,
`end_time`,
`remarks`,
`created_at`,
`updated_at`,
`open_house_type`

FROM property_open_houses;

更新2014年4月21日

根据@Aaron K的建议,我查看了https://github.com/rails/rails/issues/5982,但我担心这可能不是我的情况,因为我的表定义没有default 0的ID。

# db/schema.rb
create_table "property_open_houses", :force => true do |t|
  t.string   "mls_system",            :limit => 30, :null => false
  t.integer  "property_id",                         :null => false
  t.datetime "entered_at"
  t.datetime "modified_at"
  t.string   "mls_num",               :limit => 30, :null => false
  t.datetime "event_date"
  t.string   "end_time",              :limit => 30
  t.string   "start_time",            :limit => 30
  t.string   "open_house_type",       :limit => 30
  t.text     "remarks"
  t.string   "remote_sysid"
  t.datetime "created_at",                          :null => false
  t.datetime "updated_at",                          :null => false
  t.integer  "most_recent_import_id"
  t.datetime "expired_at"
end

我在schema.rb以及直接在数据库中检查了两者,其中基础表中的ID是自动递增的非空主键整数。我的schema.rb不包含视图,我们通过rake任务生成它们,该任务在db:migrate之后自动运行,该任务会丢弃现有视图并通过运行我之前更新中显示的原始SQL重新创建它。有趣的是,如果我在MySQL上运行describe property_open_houses_view;,ID字段将被列为默认值0.但是,对于我拥有的另一个表/视图对,即使相同的输出(ID默认为0)显示在{{ 1}},返回具有适当ID的Factory Girl模型。

行为不正确:

describe

正确行为:

mysql> describe property_open_houses_view;
+-----------------+-------------+------+-----+---------+-------+
| Field           | Type        | Null | Key | Default | Extra |
+-----------------+-------------+------+-----+---------+-------+
| id              | int(11)     | NO   |     | 0       |       |
 ... SNIP ...

mysql> describe property_open_houses;
+-----------------+--------------+------+-----+---------+----------------+
| Field           | Type         | Null | Key | Default | Extra          |
+-----------------+--------------+------+-----+---------+----------------+
| id              | int(11)      | NO   | PRI | NULL    | auto_increment |
 ... SNIP ...

我注意到的一件事是,当我创建一个行为正确的模型实例(mysql> describe properties_view; +---------------------------+----------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +---------------------------+----------------+------+-----+---------+-------+ | id | int(11) | NO | | 0 | | ... SNIP ... mysql> describe properties; +---------------------------+----------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +---------------------------+----------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | ... SNIP ... )时,生成的SQL Property没有INSERT字段,但行为不端一个(id),有这样一个字段,它的值为0,DB会忽略它,用下一个自动增量值替换它。

Property::Openhouse

更新2014年4月21日第2部分

我刚刚意识到FactoryGirl似乎不是等式的一部分,因此更新了问题标题。使用SQL (1.1ms) INSERT INTO `property_open_houses_view` (`created_at`, `end_time`, `event_date`, `expired_at`, `id`, `mls_num`, `mls_system`, `most_recent_import_id`, `open_house_type`, `property_id`, `remarks`, `start_time`, `updated_at`) VALUES ('2014-04-21 15:03:25', '6:00PM', '2014-04-14 15:02:27', NULL, 0, 'V123456', 'abcdef', NULL, NULL, 1032366, NULL, '10:00AM', '2014-04-21 15:03:25') 创建模型会引发相同的情况

create

1 个答案:

答案 0 :(得分:0)

大多数数据库不允许您直接插入视图。有一些例外(例如视图是否由单个表支持)。例如,当您在视图上尝试INSERT时,PostgreSQL将引发以下错误:

  

错误:无法插入视图“myview”

     

详细信息:不从单个表或视图中选择的视图不会自动更新。

     

提示:要启用插入视图,请提供INSTEAD OF INSERT触发器或无条件ON INSERT DO INSTEAD规则。

其他数据库可能会有不同的行为,因此请查阅他们的文档。

继续使用PostgreSQL(和Rails 4.0.x)。当ActiveRecord执行create时,SQL如下所示:

INSERT INTO "mytable" ("created_at", "foo", "updated_at", "bar")
VALUES ($1, $2, $3, $4)
RETURNING "id"
[
  ["created_at", Thu, 17 Apr 2014 23:17:32 UTC +00:00],
  ["foo", "testing"],
  ["updated_at", Thu, 17 Apr 2014 23:17:32 UTC +00:00],
  ["bar", 4.0]
]

重要的部分是RETURNING "id"。这里ActiveRecord被发送回创建的行的id值。如果您的视图使用规则假装允许create,请确保SQL具有适用于您数据库的RETURNING语法。

编辑 - MySQL DB

似乎这可能是MySQL和Rails的已知问题。有关完整问题,请参阅https://github.com/rails/rails/issues/5982