2010-12-08 19 views
13

J'ai un problème avec ActiveResource pour enregistrer un modèle avec une ressource imbriquée: Je peux charger et enregistrer une ressource non imbriquée sans problème et je peux charger une ressource plus ses ressources imbriquées, mais l'enregistrement de la ressource échoue. Ce problème se produit pour moi avec REE 1.8.7/Rails 2.3.9 et Ruby 1.9.2-p0/Rails 3.0.2. Les exemples ci-dessous sont de Rails 3/AR 3.Rails ne peut pas enregistrer une ressource imbriquée via ActiveResource

Il y a deux modèles dans mon exemple d'application:

  • Asset
  • Interface

actifs ont de nombreuses interfaces, interfaces appartiennent à des actifs .

routes.rb

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

actions de AssetController pertinentes

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 

modèles

class Asset < ActiveRecord::Base 
    has_many :interfaces 

    accepts_nested_attributes_for :interfaces 
end 

class Interface < ActiveRecord::Base 
    belongs_to :asset 
end 

Étapes de reproduire

>> 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>' 

Connexion

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' 

Tout le monde a des idées sur celui-ci? Je suis perplexe. Merci d'avance pour votre aide!

Répondre

7

ActiveResource n'a pas de support d'association prêt à l'emploi. idée intéressante de détourner les trucs nested_ * pour cela. Cela semble fonctionner pour moi:

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 

déplacez les options to_xml dans le contrôleur si vous le souhaitez. Vous pouvez également vous assurer que Interface a le bon attribut attr_protected.

+0

Cela a très bien fonctionné pour moi, merci! –

1

Vous passant des paramètres incorrects, j'attendre des attributs imbriqués pour ressembler à ceci:

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

et horodatages ids sont gérées par ActiveRecord. L'identifiant pour séparer les attributs ne semble pas avoir d'importance, tant qu'il est unique. Lorsque je génère des attributs dans un navigateur, j'utilise généralement un horodatage.

6

Cela fonctionne pour sauver le :assets paramater ainsi:

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

Cela a fonctionné très bien pour moi merci, mais, je ne comprends pas comment/pourquoi? : -S –