代码之家  ›  专栏  ›  技术社区  ›  Robin Winton

HABTM联接表的机械化批量分配错误

  •  0
  • Robin Winton  · 技术社区  · 13 年前

    问题是我得到了这个错误:

    ActiveModel::MassAssignmentSecurity::Error: Can't mass-assign protected attributes: amenity_id
    

    当我运行此代码时:

    task import_amenities: :environment do
    
      agent = Mechanize.new
    
      Kindergarten.find_all_by_public(false).each do |k| 
        p = agent.get(k.uri)
        amenities = p.search("td td tr:nth-child(11) td:nth-child(2)").text.split(/(;|,) */)
        amenities.each do |a|
          am = Amenity.find_or_create_by_name!("#{a}")
          k.update_attributes(amenity_id: am.id)
        end
      end
    end
    

    幼儿园和便利设施通过HABTM关系联系在一起,定义如下:

    幼儿园.rb

    class Kindergarten < ActiveRecord::Base
      attr_accessible :location, :name, :public, :uri, :address, :contact, 
                      :phone, :url, :email, :description, 
                      :password, :password_confirmation, :amenity_ids
      has_and_belongs_to_many :amenities
    end
    

    便利设施.rb

    class Amenity < ActiveRecord::Base
      attr_accessible :name, :kindergarten_ids
      has_and_belongs_to_many :kindergartens
    end
    

    下面是联接表的迁移:

    class CreateKindergartensAmenitiesJoinTable < ActiveRecord::Migration
      def up
    
        create_table :kindergartens_amenities, :id => false do |t|
          t.integer :kindergarten_id
          t.integer :amenity_id
        end
      end
    end
    

    该错误是由rake任务中的这一行引起的:

    k.update_attributes(amenity_id: am.id)
    

    在我完成大规模任务之前,控制台上的一切似乎都很好。我觉得我真的搞砸了,因为我以前从未使用过HABTM。

    有什么想法吗?

    1 回复  |  直到 13 年前
        1
  •  1
  •   Robin Winton    13 年前

    由于这个错误,我昨晚睡不着,但我终于找到了解决办法。

    代码中有几个问题,当我开始手动在数据库中挖掘和添加数据时,我注意到的第一个问题是联接表的名称错误。修复此问题:

    class RenameKindergartensAmenitiesTable < ActiveRecord::Migration
      def up
        rename_table :kindergartens_amenities, :amenities_kindergartens
      end
    end
    

    显然,habtm协会必须在标题中按字母顺序排列。 source

    第二个问题是我认为

    k.amenity_id = am.id
    

    将为每个现有的便利设施添加便利设施_id/幼儿园_id。事实上,k.amenity_id并没有任何意义(尤其是在许多id的情况下)。行之有效的解决方案是:

    amenities.each do |a|
      am = Amenity.find_or_create_by_name!("#{a}")
      k.update_attributes(amenity_ids: k.amenity_ids.push(am.id))
    end
    

    我还没有修改 attr_accessible 在任何地方