我在使用ActiveResource保存带有嵌套资源的模型时遇到问题:我可以加载并保存非嵌套资源而没有任何问题,我可以加载资源加上其嵌套资源,但保存资源失败。对于我来说,REE 1.8.7 / Rails 2.3.9和Ruby 1.9.2-p0 / Rails 3.0.2会出现此问题。以下示例来自Rails 3 / AR 3.
我的示例应用中有两种模式:
资产有很多接口,接口属于资产。
的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/ruby-1.9.2-p0@rails3/gems/activeresource-3.0.3/lib/active_resource/connection.rb:147:in `handle_response'
from /Users/threetee/.rvm/gems/ruby-1.9.2-p0@rails3/gems/activeresource-3.0.3/lib/active_resource/connection.rb:114:in `request'
from /Users/threetee/.rvm/gems/ruby-1.9.2-p0@rails3/gems/activeresource-3.0.3/lib/active_resource/connection.rb:91:in `block in put'
from /Users/threetee/.rvm/gems/ruby-1.9.2-p0@rails3/gems/activeresource-3.0.3/lib/active_resource/connection.rb:217:in `with_auth'
from /Users/threetee/.rvm/gems/ruby-1.9.2-p0@rails3/gems/activeresource-3.0.3/lib/active_resource/connection.rb:91:in `put'
from /Users/threetee/.rvm/gems/ruby-1.9.2-p0@rails3/gems/activeresource-3.0.3/lib/active_resource/base.rb:1307:in `update'
from /Users/threetee/.rvm/gems/ruby-1.9.2-p0@rails3/gems/activeresource-3.0.3/lib/active_resource/observing.rb:11:in `update_with_notifications'
from /Users/threetee/.rvm/gems/ruby-1.9.2-p0@rails3/gems/activeresource-3.0.3/lib/active_resource/base.rb:1117:in `save'
from /Users/threetee/.rvm/gems/ruby-1.9.2-p0@rails3/gems/activeresource-3.0.3/lib/active_resource/validations.rb:87:in `save_with_validation'
from /Users/threetee/.rvm/gems/ruby-1.9.2-p0@rails3/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'
有人对此有任何想法吗?我很难过。在此先感谢您的帮助!
答案 0 :(得分:7)
ActiveResource没有开箱即用的关联支持。有趣的想法劫持嵌套_ *的东西。这似乎对我有用:
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's。
答案 1 :(得分:6)
这也适用于使用:assets
参数进行保存:
class Asset < ActiveRecord::Base
has_many :interfaces
accepts_nested_attributes_for :interfaces
attr_accessible :interfaces, :interfaces_attributes
alias_method :interfaces=, :interfaces_attributes=
end
答案 2 :(得分:1)
你传递的参数不正确,我希望嵌套属性看起来像这样:
:asset => {
:interface_attributes => { '1' => { :name => "eth0" } }
}
时间戳和ID由ActiveRecord处理。分离属性的标识符似乎并不重要,只要它是唯一的。当我在浏览器中生成属性时,我通常使用时间戳。