创建新的时,ActiveRecord :: AssociationTypeMismatch

时间:2013-05-06 16:56:35

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

在下面创建对象“机器”时获得ActiveRecord :: AssociationTypeMismatch Component(#70354292616060) expected, got String(#70354278277000);

目标:尝试将“属性”分配给引用其他模型的模型。

问题:我想听听专家说这种操作的最佳做​​法是什么。

设置

Rails 3.2.12 / Ruby 1.9.3-p194:

型号:

class Machine < ActiveRecord::Base
  attr_accessible :cpu, :name, :ram

  belongs_to :cpu, class_name: "Component", foreign_key: "component_id"
  belongs_to :ram, class_name: "Component", foreign_key: "component_id"
end

class Component < ActiveRecord::Base
  attr_accessible :name
  has_many :machines
end

机器视图:

  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :cpu %><br />
    <%= f.collection_select :cpu, Component.all, :id, :name %>
  </div>
  <div class="field">
    <%= f.label :ram %><br />
    <%= f.collection_select :ram, Component.all, :id, :name %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>

程序

  1. 为Component创建少量对象,以便id:1 name:"cpu1"&amp; id:2 name:"ram1"
  2. 转到machines_path并创建Machine,从下拉列表中选择cpu1和ram1
  3. 提交Component(#70354292616060) expected, got String(#70354278277000)
  4. 时出现以下错误

    我尝试更改:cpu和:ram在View中:cpu_id和:ram_id。此后,我可以无错误地创建模型。但是我无法访问cpu&amp; ram直接来自机器;

    1.9.3-p194 :001 > Machine.first
      Machine Load (0.1ms)  SELECT "machines".* FROM "machines" LIMIT 1
     => #<Machine id: 2, name: "test", cpu_id: 1, ram_id: 1, created_at: "2013-05-06     16:42:47", updated_at: "2013-05-06 16:42:47"> 
    1.9.3-p194 :002 > Machine.first.cpu
      Machine Load (0.2ms)  SELECT "machines".* FROM "machines" LIMIT 1
     => nil 
    1.9.3-p194 :003 > Machine.first.ram
      Machine Load (0.2ms)  SELECT "machines".* FROM "machines" LIMIT 1
     => nil 
    

    所以我必须创建以下模型方法

      class Machine < ActiveRecord::Base
    
      (snip)
    
      def cpu
        Component.find_by_id(self.cpu_id)
      end
    
      def ram
        Component.find_by_id(self.ram_id)
      end
    

    然后我可以得到预期的输出

    1.9.3-p194 :002 > Machine.first.cpu.name
      Machine Load (0.2ms)  SELECT "machines".* FROM "machines" LIMIT 1
      Component Load (0.2ms)  SELECT "components".* FROM "components" WHERE "components"."id" = 1 LIMIT 1
      => "CPU1" 
    

    但我觉得这是多余的,并且正在寻找一种更简单的方法。

    感谢是否有任何建议。

2 个答案:

答案 0 :(得分:0)

因此,如果我正确阅读,您需要能够在表单中将字段设置为其他模型。

这是嵌套属性。

form_for @components内执行form_for @machines,并为attr_accessible模型中的这些字段授予Machine权限

这很有用http://railscasts.com/episodes/196-nested-model-form-part-1

答案 1 :(得分:0)

首先,让您的选择框与cpu_id和ram_id一起使用是正确的。如果你没有那么rails(稍微简化)

machine.cpu = params[:machine][:cpu]

Params总是字符串,所以这是尝试为关联分配一个字符串,因此关于它的错误期待一个组件但是得到一个字符串。

你的第二个问题在于如何声明你的关联:你已经设置了ram和cpu关联来使用component_id列来存储相应列的id,这显然是行不通的。相反,您可能希望CPU关联使用cpu_id列并将ram关联到ram_id列。这实际上是默认设置 - 删除你传递给那些属于的调用的外键选项,你应该没问题。

组件上的关联虽然需要外键选项。最简单的方法是为组件充当CPU的机器和ram的另一个机器建立一个关联。您可以考虑设置单表继承,在这种情况下,CPU子类只有与cpu_id相关的关联,而ram子类只有与ram_id相关的关联