Search code examples
ruby-on-railsrubynested-formsnested-attributes

Rails: Not permitting :id of nested model leads to automatic generation of new instances. Why?


I have a conceptual doubt regarding nested models, and I hope I will make myself clear in this question.

I have 3 models, A, B, and C. A accepts nested attributes for B and C. On AController#new I write @a = A.new, @a.b.build, @a.c.build (I will share the code below).

Defining A's parameters, I permit B's parameters and C's parameters. Problem: I had forgotten to permit C's :id.

Thus, whenever I would edit an instance of A on my website (say, at '/a/1/edit'), it would automatically create new instances of C.

Diagnosing the problem was very easy (I just spotted that C's :id was missing, and inferred that it was the issue), but I wonder why that happens. Does anyone have insight? Details of my code follow.

a.rb

has_many :b
has_many :c    
accepts_nested_attributes_for :b
accepts_nested_attributes_for :c

a_controlle.rb

def new
    @a = A.new
    @a = @a.b.build
    @a = @a.c.build
end

def edit
    @a = A.find(params[:id])
end

def update
    if A.find(params[:id]).update_attributes(a_params)
    #SOME CODE
end

def create
    @a = A.new(a_params)
    #SOME CODE
end

private

def a_params
    params.require[:a].permit(:a_name, b_attributes: [:id, :b_name],
    c_attributes: [:c_name]) ## SEE, I had forgotten C's :id.
end

And both A/new.html.erb and A/edit.html.erb have fields_for B and C.

So, does anyone know why anytime I would access A/[:id]/edit it would generate new instances of C, given that I had forgotten to permit its :id?


Solution

  • That's by design. If one use accepts_nested_attributes_for :c and sends attributes for C, that object is created if there is no :id param in params for C (in c_attributes).

    So I suppose you have a form with nested attributes for C and B models and every time you submit your form you send your attributes for A,B and C objects. Every time you send your c_attributes without :id new object is created.

    You can experiment and create form for only A oject or A and B objects to see that no C objects are created or edited.

    I hope that helps you a bit to understand what's going on.