2009-05-10 4 views
30

Comment puis-je passer JSON à une application RAILS il sera créé des objets enfants imbriqués dans une relation has_many?création d'objets nichés JSON dans Rails

Voici ce que j'ai jusqu'à présent:

Deux objets de modèle.

class Commute < ActiveRecord::Base 
    has_many :locations 
    accepts_nested_attributes_for :locations, :allow_destroy => true 
end 

class Location < ActiveRecord::Base 
    belongs_to :commute 
end 

Avec Commute, j'ai configuré un contrôleur standard. J'aimerais pouvoir créer un objet Commute ainsi que plusieurs objets Emplacement enfant dans un seul appel REST à l'aide de JSON. J'ai essayé des choses comme ça:

curl -H "Content-Type:application/json" -H "Accept:application/json" 
-d "{\"commute\":{\"minutes\":0, 
\"startTime\":\"Wed May 06 22:14:12 EDT 2009\", 
\"locations\":[{\"latitude\":\"40.4220061\", 
\"longitude\":\"40.4220061\"}]}}" http://localhost:3000/commutes 

Ou plus lisible, le JSON est:

{ 
    "commute": { 
     "minutes": 0, 
     "startTime": "Wed May 06 22:14:12 EDT 2009", 
     "locations": [ 
      { 
       "latitude": "40.4220061", 
       "longitude": "40.4220061" 
      } 
     ] 
    } 
} 

Quand j'exécute, je reçois cette sortie:

Processing CommutesController#create (for 127.0.0.1 at 2009-05-10 09:48:04) [POST] 
    Parameters: {"commute"=>{"minutes"=>0, "locations"=>[{"latitude"=>"40.4220061", "longitude"=>"40.4220061"}], "startTime"=>"Wed May 06 22:14:12 EDT 2009"}} 

ActiveRecord::AssociationTypeMismatch (Location(#19300550) expected, got HashWithIndifferentAccess(#2654720)): 
    app/controllers/commutes_controller.rb:46:in `new' 
    app/controllers/commutes_controller.rb:46:in `create' 

Il semble Tout comme les emplacements, le tableau JSON est en cours de lecture mais n'est pas interprété comme un objet Location.

Je peux facilement changer le client ou le serveur, la solution pourrait venir de chaque côté.

Alors, est-RAILS rendre cela facile pour moi de le faire? Ou ai-je besoin d'ajouter un support pour cela à mon objet Commute? Peut-être ajouter une méthode from_json?

Merci pour toute aide.


Comme j'ai travaillé à travers cela, une solution qui fonctionne est de modifier mon contrôleur. Mais cela ne semble pas être la façon de le faire, alors s'il vous plaît laissez-moi savoir s'il y a un meilleur moyen.

def create 
    locations = params[:commute].delete("locations"); 
    @commute = Commute.new(params[:commute]) 

    result = @commute.save 

    if locations 
     locations.each do |location| 
     @commute.locations.create(location) 
     end 
    end 


    respond_to do |format| 
     if result 
     flash[:notice] = 'Commute was successfully created.' 
     format.html { redirect_to(@commute) } 
     format.xml { render :xml => @commute, :status => :created, :location => @commute } 
     else 
     format.html { render :action => "new" } 
     format.xml { render :xml => @commute.errors, :status => :unprocessable_entity } 
     end 
    end 
    end 

Répondre

35

figured it out, les lieux objet aurait été appelé locations_attributes pour correspondre avec les rails imbriqués schéma de nommage création d'objets. Après cela, cela fonctionne parfaitement avec un contrôleur Rails par défaut.

{ 
    "commute": { 
     "minutes": 0, 
     "startTime": "Wed May 06 22:14:12 EDT 2009", 
     "locations_attributes": [ 
      { 
       "latitude": "40.4220061", 
       "longitude": "40.4220061" 
      } 
     ] 
    } 
} 
+1

Vous semblez être en mesure de contrôler le JSON source, mais si vous ne pouviez pas, comment géreriez-vous les "emplacements"? – Jerome

+0

Jetez un oeil, je viens de poster une modification d'une réponse qui a été supprimée. –

+0

Pour toute personne ayant encore des problèmes avec cela, vous devez autoriser manuellement les attributs de votre contrôleur. Exemple: 'params.require (: commute) .permit (: minutes,: startTime, locations_attributes: [: latitude,: longitude])' – Kevin

0

Si vous ne pouvez pas facilement changer le JSON vous travaillez, vous pouvez simplement mettre en œuvre new sur vos modèles. J'utilise ce qui suit pour disputer la JSON dans la forme prévue, ce qui dans mon cas implique la suppression de la clé « id » et quelques qui n'existent pas dans mon modèle local. Je l'ai mis en œuvre dans application_record.rb et des cas spéciaux au sein de chaque modèle.

def self.new(properties = {}) 
    super properties.select { |attr, _val| 
    (['id'] + attribute_types.keys).include?(attr.to_s) 
} 
Questions connexes