Search code examples
rubyjsonapiruby-on-rails-4strong-parameters

Strong params: How to process nested json code?


I'm trying to write an update method that processes JSON. The JSON looks like this:

{
  "organization": {
    "id": 1,
    "nodes": [
      {
        "id": 1,
        "title": "Hello",
        "description": "My description."
      },
      {
        "id": 101,
        "title": "fdhgh",
        "description": "My description."
      }
    ]
  }
}

My update method is as follows:

  def update
    organization = Organization.find(params[:id])
    nodes = params[:organization][:nodes]
    nodes.each do |node|
      n = Node.find(node[:id])
      unless n.update_attributes(node_params)
        render json: organization, status: :failed
      end
    end
    render json: diagram, status: :ok
  end

  private
    def node_params
      params.require(:organization).permit(nodes: [:title, :description])
    end

Unfortunately, n.update_attributes(node_params) generates:

Unpermitted parameter: id
Unpermitted parameter: id
Unpermitted parameter: id
   (0.2ms)  BEGIN
   (0.3ms)  ROLLBACK
*** ActiveRecord::UnknownAttributeError Exception: unknown attribute 'nodes' for Node.

Does anyone see what I'm doing wrong and to write this update method?


Solution

  • On the unless n.update_attributes(node_params) line, you're trying to update Node n with nodes_params, which are all of the nodes from your JSON minus the ids:

    {"nodes"=>[{"title"=>"Hello", "description"=>"My description."}, {"title"=>"fdhgh", "description"=>"My description."}]}

    You could just add :id as a permitted node parameter, cut out the nodes assignment step, iterate over node_params instead, and just omit the :id when updating Node n. E.g.,

    def update
      organization = Organization.find(params[:id])
      node_params.each do |node|
        n = Node.find(node[:id])
        unless n.update_attributes(node.except(:id))
          render json: organization, status: :failed
        end
      end
      render json: diagram, status: :ok
    end
    
    private
      def node_params
        params.require(:organization).permit(nodes: [:id, :title, :description])
      end