how do i build a nested many-to-many relationship in rails?

From looking at https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html I think the data format that Rails is normally going to expect will look something like:

{
  "group": {
    "name": "Pink Floyd",
    "notes": "",
    "roles_attributes": [
      { "artist_id": 3445 },
      { "artist_id": 3447 }
    ]
  }
}

with a permit statement that looks something like (note the . before permit has moved):

params.require(:group).
    permit(:name, :notes, roles_attributes: [:artist_id])

I think you have a few options here:

  1. Change the data format coming into the action.
  2. Craft a permit statement that works with your current data (not sure how tricky that is), you can test your current version in the console with:
params = ActionController::Parameters.new({
  "data": {
    "attributes": {
      "name": "Pink Floyd",
      "notes": "",
    },
    "relationships": {
      "artists": [{ type: "artist", "id": 3445 }, { type: "artist", "id": 3447 }]
    }
  }
})

group_params = params.require(:data).
    permit(attributes: [:name, :notes],
      relationships: [:artists])

group_params.to_h.inspect

and then restructure the data to a form the model will accept; or

  1. Restructure the data before you try to permit it e.g. something like:
def group_params
    params_hash = params.to_unsafe_h

    new_params_hash = {
      "group": params_hash["data"]["attributes"].merge({
        "roles_attributes": params_hash["data"]["relationships"]["artists"].
            map { |a| { "artist_id": a["id"] } }
      })
    }

    new_params = ActionController::Parameters.new(new_params_hash)

    new_params.require(:group).
        permit(:name, :notes, roles_attributes: [:artist_id])
end

But … I’m sort of hopeful that I’m totally wrong and someone else will come along with a better solution to this stuff.

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top