2010-12-08 79 views
13

我有一个问题,使用ActiveResource保存模型与嵌套的资源:我可以加载和保存没有问题的非嵌套资源,我可以加载资源加上它的嵌套资源,但保存资源失败。对于REE 1.8.7/Rails 2.3.9和Ruby 1.9.2-p0/Rails 3.0.2,我会遇到这个问题。下面的例子是从Rails的3/AR 3.Rails无法通过ActiveResource保存嵌套的资源

有两种型号在我的示例应用程序:

  • 资产
  • 接口

资产有多个接口,接口属于资产。

的routes.rb

Rails3Testapp::Application.routes.draw do 
resources :interfaces 
resources :assets 
end 

相关AssetController行动

def index 
    @assets = Asset.all 

    respond_to do |format| 
     format.html # index.html.erb 
     format.xml { render :xml => @assets, :include => [ :interfaces ] } 
    end 
    end 

    def show 
    @asset = Asset.find(params[:id]) 

    respond_to do |format| 
     format.html # show.html.erb 
     format.xml { render :xml => @asset, :include => [ :interfaces ] } 
    end 
    end 

    def update 
    @asset = Asset.find(params[:id]) 

    respond_to do |format| 
     if @asset.update_attributes(params[:asset]) 
     format.html { redirect_to(@asset, :notice => 'Asset was successfully updated.') } 
     format.xml { head :ok } 
     else 
     format.html { render :action => "edit" } 
     format.xml { render :xml => @asset.errors, :status => :unprocessable_entity } 
     end 
    end 
    end 

模式

class Asset < ActiveRecord::Base 
    has_many :interfaces 

    accepts_nested_attributes_for :interfaces 
end 

class Interface < ActiveRecord::Base 
    belongs_to :asset 
end 

个步骤来复制

>> require 'active_resource' 
=> true 
>> class Asset < ActiveResource::Base 
>> self.site = 'http://localhost:3000/' 
>> end 
>> test_asset = Asset.first 
=> #<Asset:0x00000100a86690 @attributes={"created_at"=>2010-12-07 16:24:59 UTC, "description"=>"Testing testing", "id"=>1, "name"=>"Test Asset #1", "updated_at"=>2010-12-07 16:24:59 UTC, "interfaces"=>[#<Asset::Interface:0x00000100a7dc98 @attributes={"asset_id"=>1, "created_at"=>2010-12-07 18:01:15 UTC, "id"=>1, "name"=>"eth0", "updated_at"=>2010-12-07 18:01:15 UTC}, @prefix_options={}>, #<Asset::Interface:0x00000100a7a8e0 @attributes={"asset_id"=>1, "created_at"=>2010-12-07 18:04:49 UTC, "id"=>2, "name"=>"eth1", "updated_at"=>2010-12-07 18:04:49 UTC}, @prefix_options={}>]}, @prefix_options={}> 
>> test_asset.save 
ActiveResource::ServerError: Failed. Response code = 500. Response message = Internal Server Error . 
    from /Users/threetee/.rvm/gems/[email protected]/gems/activeresource-3.0.3/lib/active_resource/connection.rb:147:in `handle_response' 
    from /Users/threetee/.rvm/gems/[email protected]/gems/activeresource-3.0.3/lib/active_resource/connection.rb:114:in `request' 
    from /Users/threetee/.rvm/gems/[email protected]/gems/activeresource-3.0.3/lib/active_resource/connection.rb:91:in `block in put' 
    from /Users/threetee/.rvm/gems/[email protected]/gems/activeresource-3.0.3/lib/active_resource/connection.rb:217:in `with_auth' 
    from /Users/threetee/.rvm/gems/[email protected]/gems/activeresource-3.0.3/lib/active_resource/connection.rb:91:in `put' 
    from /Users/threetee/.rvm/gems/[email protected]/gems/activeresource-3.0.3/lib/active_resource/base.rb:1307:in `update' 
    from /Users/threetee/.rvm/gems/[email protected]/gems/activeresource-3.0.3/lib/active_resource/observing.rb:11:in `update_with_notifications' 
    from /Users/threetee/.rvm/gems/[email protected]/gems/activeresource-3.0.3/lib/active_resource/base.rb:1117:in `save' 
    from /Users/threetee/.rvm/gems/[email protected]/gems/activeresource-3.0.3/lib/active_resource/validations.rb:87:in `save_with_validation' 
    from /Users/threetee/.rvm/gems/[email protected]/gems/activeresource-3.0.3/lib/active_resource/observing.rb:11:in `save_with_notifications' 
    from (irb):33 
    from /Users/threetee/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `<main>' 

登录

Started PUT "/assets/1.xml" for 127.0.0.1 at 2010-12-07 11:58:40 -0800 
    Processing by AssetsController#update as XML 
    Parameters: {"asset"=>{"created_at"=>2010-12-07 16:24:59 UTC, "description"=>"Testing testing", "id"=>1, "name"=>"Test Asset #1", "updated_at"=>2010-12-07 16:24:59 UTC, "interfaces"=>[{"asset_id"=>1, "created_at"=>2010-12-07 18:01:15 UTC, "id"=>1, "name"=>"eth0", "updated_at"=>2010-12-07 18:01:15 UTC}, {"asset_id"=>1, "created_at"=>2010-12-07 18:04:49 UTC, "id"=>2, "name"=>"eth1", "updated_at"=>2010-12-07 18:04:49 UTC}]}, "id"=>"1"} 
    SQL (0.8ms) SELECT name 
FROM sqlite_master 
WHERE type = 'table' AND NOT name = 'sqlite_sequence' 

    Asset Load (0.2ms) SELECT "assets".* FROM "assets" WHERE ("assets"."id" = 1) LIMIT 1 
WARNING: Can't mass-assign protected attributes: id 
Completed in 161ms 

ActiveRecord::AssociationTypeMismatch (Interface(#2154409400) expected, got ActiveSupport::HashWithIndifferentAccess(#2154546040)): 
    app/controllers/assets_controller.rb:62:in `block in update' 
    app/controllers/assets_controller.rb:61:in `update' 

任何人对此有一个什么想法?我很难过。预先感谢任何帮助!

回答

7

ActiveResource不具备开箱即用的关联支持。有趣的想法劫持nested_ *这个东西。这似乎适用于我:

class Asset < ActiveRecord::Base 
    has_many :interfaces 
    accepts_nested_attributes_for :interfaces 
    alias interfaces_attributes interfaces 

    def to_xml(options = {}) 
    super(options.merge({:methods => :interfaces_attributes})) 
    end 
end 

将to_xml选项移动到控制器,如果你喜欢。可能还希望确保Interface具有正确的attr_protected。

+0

这对我的工作很好,谢谢! – 2010-12-08 04:18:18

1

你传递不正确的参数,我希望嵌套的属性看起来像这样:

:asset => { 
    :interface_attributes => { '1' => { :name => "eth0" } } 
} 

时间戳和ID由ActiveRecord的处理。分离属性的标识符似乎并不重要,只要它是唯一的即可。当我在浏览器中生成属性时,我通常使用时间戳。

6

这适用于与:assets节省paramater还有:

class Asset < ActiveRecord::Base 
    has_many :interfaces 
    accepts_nested_attributes_for :interfaces 
    attr_accessible :interfaces, :interfaces_attributes 
    alias_method :interfaces=, :interfaces_attributes= 
end 
+0

这对我很好,谢谢,但是,我不明白如何/为什么? :-S – 2012-11-09 22:15:30