Seanvm Seanvm - 5 months ago 9
Ruby Question

Rails 4 - Iterate through nested JSON params

I'm passing nested JSON into rails like so:

{
"product": {
"vendor": "Acme",
"categories":
{
"id": "3",
"method": "remove",
},
"categories":
{
"id": "4"
}
}
}


in order to update the category on a product. I am trying to iterate through the categories attribute in my products_controller so that I can add/remove the product to multiple categories at once:

def updateCategory
@product = Product.find(params[:id])

params[:product][:categories].each do |u|
@category = Category.find_by(id: params[:product][:categories][:id])
if params[:product][:categories][:method] == "remove"
@product.remove_from_category(@category)
else
@product.add_to_category(@category)
end
end
end


However, this only uses the second 'categories' ID in the update and doesn't iterate through both.
Example response JSON:

{
"product": {
"id": 20,
"title": "Heavy Duty Aluminum Chair",
"product_price": "47.47",
"vendor": "Acme",
"categories": [
{
"id": 4,
"title": "Category 4"
}
]
}
}


As you can see, it only added the category with ID = 4, and skipped over Category 3.

I'm fairly new to rails so I know I'm probably missing something obvious here. I've played around with the format of the JSON I'm passing in as well but it only made things worse.

Answer

You need to change your JSON structure. As you currently have it, the second "categories" reference will override the first one since you can only have 1 instance of a key. To get what you want, you should change it to:

{
  "product": {
    "vendor": "Acme",
    "categories": [
        {
            "id": "3",
            "method": "remove",
        }, 
        {
            "id": "4"
        }
    ]
  }
}

You will also need to change your ruby code to look like:

def updateCategory
    @product = Product.find(params[:id])

    params[:product][:categories].each do |u|
      @category = Category.find_by(id: u[:id])
      if u[:method] == "remove"
        @product.remove_from_category(@category)
      else
        @product.add_to_category(@category)
      end
    end
end