¿Cómo transfiero JSON a una aplicación RAILS para que cree objetos secundarios anidados en una relación has_many?Creación de objetos anidados con JSON en Rails
Esto es lo que tengo hasta ahora:
Dos objetos del modelo.
class Commute < ActiveRecord::Base
has_many :locations
accepts_nested_attributes_for :locations, :allow_destroy => true
end
class Location < ActiveRecord::Base
belongs_to :commute
end
Con Conmutar, tengo un controlador estándar configurado. Me gustaría poder crear un objeto Commute así como varios objetos de ubicación secundarios en una sola llamada REST usando JSON. He estado tratando de cosas como esta:
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
O más legible, el JSON es:
{
"commute": {
"minutes": 0,
"startTime": "Wed May 06 22:14:12 EDT 2009",
"locations": [
{
"latitude": "40.4220061",
"longitude": "40.4220061"
}
]
}
}
Cuando ejecuto esto, me da este resultado:
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'
Parece como las ubicaciones en las que se lee la matriz JSON, pero no se interpreta como un objeto Ubicación.
Puedo cambiar fácilmente el cliente o el servidor, por lo que la solución podría provenir de cualquiera de los lados.
Entonces, ¿RAILS me facilita esto? ¿O necesito agregar algún soporte para esto a mi objeto Commute? Tal vez agregar un método from_json?
Gracias por cualquier ayuda.
Como he estado trabajando en esto, una solución que funciona es modificar mi controlador. Pero esta no parece ser la forma de "dardos" para hacerlo, así que por favor díganme si hay una manera mejor.
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
Parece que puede controlar la fuente JSON, pero ¿qué pasa si no puede, cómo manejaría "ubicaciones"? – Jerome
Echa un vistazo, acabo de publicar una edición de una respuesta que se eliminó. –
Para cualquiera que todavía tenga problemas con esto, debe permitir manualmente los atributos en su controlador. Ejemplo: 'params.require (: conmutar) .permit (: minutos,: startTime, locations_attributes: [: latitude,: longitude])' – Kevin