0

聪明人,

请帮我解决我的 has_many 多态对象创建问题。

我在两个对象之间有一个多态的 has_many 关系,中间有一个连接表。一方面是首字母缩略词(和其他对象),另一方面是类别。在它们之间,我在两个对象之间有一个连接对象。

我无法成功创建带有类别的首字母缩写词。但是,我可以创建一个没有类别的首字母缩写词,然后将该类别添加到现有的首字母缩写词中。

我的模型对象看起来像下面的代码:

class Acronym < ActiveRecord::Base
  has_many :category_belongings, :as => :categorizable, :dependent => :delete_all
  has_many :categories, :through => :category_belongings
end

class Category < ActiveRecord::Base
  has_many :category_belongings, :dependent => :delete_all
  has_many :acronyms, :through => :category_belongings, :source => :categorizable, :source_type => 'Acronym'
end

class CategoryBelonging < ActiveRecord::Base
  belongs_to :categorizable, :polymorphic => true
  belongs_to :category
end

作为参考,我删除了一些额外的字段和不相关的规则。我还重构了我的代码,使其看起来像这里的示例: 设置多态 has_many :through 关系

通过我的 Rails 应用程序/rails 控制台,我能够:

  • 成功创建没有任何类别的首字母缩写词
  • 成功创建类别
  • 通过更新首字母缩写词成功地将现有类别添加到现有首字母缩写词

但是,我无法使用现有类别创建新的首字母缩略词。我可以在日志中看到 Rails 尝试执行以下操作:

  1. 从帖子中收集参数。这些参数包括 Acronym 表中的列以及类别 ID
  2. 检查类别是否存在。确实如此。
  3. 检查首字母缩写词是否存在。它不是。
  4. 使用所有列参数将新 Acronym 插入数据库
  5. 尝试在连接表中插入新条目。这就是错误所在。此插入的 SQL 包含 Acronym ID 的 Nil 值。
  6. 回滚我的更改。

    Processing by Admin::AcronymsController#create as HTML
      Parameters: {"utf8"=>"✓", "authenticity_token"=>"/uquz5FvtMh0QWP5NoWwTO9FMMEC9rsMTrTj4WUNxxE=", "acronym"=>{"name"=>"A Test Acronym", "definition"=>"A Test Definition", "explanation"=>"", "category_ids"=>["1", ""], "state"=>"unapproved"}, "commit"=>"Create Acronym"}
      Category Load (0.4ms)  SELECT "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT 1  [["id", 1]]
       (0.3ms)  BEGIN
      Category Exists (0.6ms)  SELECT 1 AS one FROM "categories" WHERE ("categories"."name" = 'Internet' AND "categories"."id" != 1) LIMIT 1
      Acronym Exists (26.0ms)  SELECT 1 AS one FROM "acronyms" WHERE "acronyms"."name" = 'A Test Acronym' LIMIT 1
      SQL (18.1ms)  INSERT INTO "acronyms" ("definition", "explanation", "improvement_reason", "likes_count", "name", "state", "submitter_id") VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING "id"  [["definition", "A Test Definition"], ["explanation", ""], ["improvement_reason", nil], ["likes_count", 0], ["name", "A Test Acronym"], ["state", "unapproved"], ["submitter_id", nil]]
      SQL (55.8ms)  INSERT INTO "category_belongings" ("categorizable_id", "categorizable_type", "category_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["categorizable_id", nil], ["categorizable_type", "Acronym"], ["category_id", 1], ["created_at", Thu, 28 Feb 2013 23:03:48 UTC +00:00], ["updated_at", Thu, 28 Feb 2013 23:03:48 UTC +00:00]]
    PG::Error: ERROR:  null value in column "categorizable_id" violates not-null constraint
    : INSERT INTO "category_belongings" ("categorizable_id", "categorizable_type", "category_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id"
       (0.3ms)  ROLLBACK
    

我假设在 Acronym 插入时会创建一个 acronym_id,但我没有看到任何输出表明该 acronym_id 的值是什么。对我来说,错误显然是当我尝试将新行插入 category_belongings 时 acronym_id 为 Nil。我是否需要以某种方式将 acronym_id 指向 categorizable_id?如果是这样,我该怎么做?

我是 Rails 新手,我正在尝试维护和改进现有系统。谢谢你的帮助。

4

2 回答 2

1

根据您要执行的操作,您需要使用accepts_nested_attributes_for. 这将允许您在创建首字母缩写词时创建类别。以下是您应该如何设置它。

class Acronym < ActiveRecord::Base
  has_many :categories, :through => :category_belongings
  has_many :category_belongings, :dependent => :destroy
  accepts_nested_attributes_for :acronyms

  attr_accessible :acronyms_attributes      
end

class Category < ActiveRecord::Base
  has_many :acronyms, :through => :category_belongings
  has_many :category_belongings, :dependent => :destroy     
end

class CategoryBelonging < ActiveRecord::Base
  belongs_to :acronym
  belongs_to :category
end

此设置将允许您在创建首字母缩写词时嵌套表单并创建类别。要阅读有关所有选项accepts_nested_attributes_for的更多信息,请查看Rails API。这个Railscast也有一些关于嵌套表单的好信息。

于 2013-03-01T00:50:27.803 回答
0

看来我的代码很好——我被 Rails 的错误所困扰。我通过根据这些说明启用安全补丁将我的 rails 版本移动到 3.2.8 解决了这个问题。之后,一切正常,无需更改代码。

https://github.com/rails/rails/issues/8269#issuecomment-10518099

于 2013-03-05T15:08:25.330 回答