0

To put my question in context, I have a form that has many fields. Each field can be at the root or a children of another field (hierarchy using Closure Table in my database). I don't have any problem building the hierarchies table, but I have a problem setting the form_id on the children fields.

Here is my schema:

create_table "fields", force: :cascade do |t|
    t.integer  "form_id", null: false
    [...]
    t.integer  "parent_id"
end

And my models (stripped down for simplicity):

class Field < ActiveRecord::Base
    has_many :fields,
             foreign_key: :parent_id,
             inverse_of: :field,
             dependent: :destroy

    belongs_to :form, inverse_of: :fields, touch: true
    belongs_to :field,
               foreign_key: :parent_id,
               inverse_of: :fields
end

class Form < ActiveRecord::Base
    has_many :fields,
             inverse_of: :form,
             dependent: :destroy
end

If I save my children fields using nested form, I get this error: ERROR: null value in column "form_id" violates not-null constraint. The form_id is not passed if I do: Form.find(1).fields.first.fields.new for example.

Is there a way to set this automatically? The parent_id is set automatically.

EDIT

Example of the params stack. I use Trailblazer architecture with Reform.

{
    [...]
    "fields"=>[{
        "id"=>"11",
        "_destroy"=>"false",
        "position"=>"1",
        "value"=>"Foobar",
        "fields"=>[{
            "id"=>"",
            "_destroy"=>"false",
            "position"=>"1",
            "value"=>"Foobar child"
        }]
    }]
}
Annie Caron
  • 437
  • 1
  • 5
  • 15
  • interesting, last time I saw something like this was in drupal's database, first of first, i think it's better to name `:fields` to `:children_fields` and `:field` to `:parent_field` to understand them better. since you want the `:form_id` of the parent field to be passed down to the `children_fields`, can't you just initialize them from the start? Or create a `before_create` to set it? – lusketeer Jun 02 '16 at 13:52
  • I prefer to keep it `fields` only, but this is mostly personal to this point... I understand that is it easier to understand though! I don't want to use `before_create` or any other triggers if it is possible since I'm using the Trailblazer stack with Reform contracts. I want to use less automagick things and I want to keep my model very thin for separation of concerns. Even with the `before_create`, it will have to query back the parent when you do `field.form_id`? – Annie Caron Jun 02 '16 at 13:57
  • can we see the nested form for the children fields? also some codes from the controller action would be nice too – lusketeer Jun 02 '16 at 14:01
  • @lusketeer I added an example of `params`, but I don't think it is useful for this question... Like I said, this: `Form.find(1).fields.first.fields.new({...})` doesn't pass `form_id` so it will not pass either if my params doesn't have `form_id` (which I will not pass from a form in which a user can edit any datas for security reason). Any other idea? – Annie Caron Jun 02 '16 at 14:10
  • why cant you just set the form_id to `@form.id` in your controller action? – lusketeer Jun 02 '16 at 14:17
  • @lusketeer `params[:form_id]` if set at the root of the `params` with the routes (if it is in edit mode), but it is not set inside the `fields`. I will have to loop through the `params` and set it. The reality is that I can create form and fields at the same time so the form id doesn't exist sometime. The `before_create` works perfectly for that case, but I was wondering if there was another approach! Thanks for your help – Annie Caron Jun 02 '16 at 14:23
  • yea no worries, sorry can't be more helpful, good luck – lusketeer Jun 02 '16 at 14:27

0 Answers0