moiristo / deep_cloneable

This gem gives every ActiveRecord::Base object the possibility to do a deep clone that includes user specified associations.
MIT License
785 stars 89 forks source link

Prefill a nested element with simple_form and deep_cloneable #73

Closed Sashkan closed 7 years ago

Sashkan commented 7 years ago

Is it possible to pre-fill a simple_fields_for input with datas from another object ?

I have a User object. User has_one Backpack, Backpack has many Pockets, and Pocket has_many Items

When building my form, i'm using

        <%= f.simple_fields_for :backpack do |backpack| %>
          <%= render 'backpack', f:backpack %>
        <% end %>

Now, when I'm on users#new, the whole form is empty. I would like to initialize the Backpack fields with datas from another Backpack object, is it possible ? I tried by doing this:

        <%= f.simple_fields_for :backpack, @backpack do |backpack| %>
          <%= render 'backpack', f:backpack %>
        <% end %>

along with this in my UsersController:

    @user = User.new
    @backpack = Backpack.find(1).deep_clone include: [ :pockets, { pockets: :items } ]

But this doesn't work: for some reason, the Backpack fields are filled, but his Pockets and their Items are empty (Only the direct attributes of Backpack are pre-filled).

Did I miss something ?

moiristo commented 7 years ago

I guess it might have to do with the way simple_form accesses the associations. Have you verified that the objects are in fact in the cloned object? How are you rendering the :pockets and items fields anyway? Can you show me the backpack form?

aldrinmartoq commented 7 years ago

I have a very similar problem, I need to clone a Form record without saving it, it has a many-to-many relationship to Field records, and the join table has attributes like required and position of the field in the form.

class Form
  # attributes :name
  has_many :form_fields
  has_many :fields, through: :form_fields

class Field
  # attributes :name
  has_many :form_fields
  has_many :forms, through: :form_fields

class FormField
  # attributes :position, :required
  belongs_to :field
  belongs_to :form
# Original form
2.3.3 :035 > form = Form.find 84
  Form Load (0.5ms)  SELECT  "forms".* FROM "forms" WHERE "forms"."id" = $1 LIMIT 1  [["id", 84]]
+----+------+---------------------------+---------------------------+
| id | name | created_at                | updated_at                |
+----+------+---------------------------+---------------------------+
| 84 | OK   | 2017-04-08 13:12:35 -0300 | 2017-04-08 13:12:35 -0300 |
+----+------+---------------------------+---------------------------+
1 row in set
2.3.3 :036 > form.form_fields
  FormField Load (0.6ms)  SELECT "form_fields".* FROM "form_fields" WHERE "form_fields"."form_id" = $1  [["form_id", 84]]
+-----+---------+----------+----------+---------------------------+---------------------------+----------+
| id  | form_id | field_id | position | created_at                | updated_at                | required |
+-----+---------+----------+----------+---------------------------+---------------------------+----------+
| 218 | 84      | 45       | 20       | 2017-04-08 13:12:36 -0300 | 2017-04-08 13:12:36 -0300 | false    |
| 219 | 84      | 46       | 30       | 2017-04-08 13:12:36 -0300 | 2017-04-08 13:12:36 -0300 | false    |
| 220 | 84      | 47       | 40       | 2017-04-08 13:12:36 -0300 | 2017-04-08 13:12:36 -0300 | false    |
| 221 | 84      | 57       | 50       | 2017-04-08 13:12:36 -0300 | 2017-04-08 13:12:36 -0300 | false    |
| 222 | 84      | 53       | 10       | 2017-04-08 13:12:36 -0300 | 2017-04-08 13:12:36 -0300 | false    |
| 217 | 84      | 67       | 60       | 2017-04-08 13:12:35 -0300 | 2017-04-08 13:31:01 -0300 | true     |
+-----+---------+----------+----------+---------------------------+---------------------------+----------+
6 rows in set
2.3.3 :037 > form.fields
  Field Load (0.9ms)  SELECT "fields".* FROM "fields" INNER JOIN "form_fields" ON "fields"."id" = "form_fields"."field_id" WHERE "form_fields"."form_id" = $1  [["form_id", 84]]
+----+-----------------------+---------------------------+---------------------------+
| id | name                  | created_at                | updated_at                |
+----+-----------------------+---------------------------+---------------------------+
| 45 | RUT                   | 2017-03-29 16:11:18 -0300 | 2017-03-30 12:31:22 -0300 |
| 46 | Datos de Contacto     | 2017-03-29 16:12:11 -0300 | 2017-03-31 15:56:47 -0300 |
| 47 | Descripción Cliente   | 2017-03-29 16:15:18 -0300 | 2017-03-30 12:31:22 -0300 |
| 57 | Productos y Servicios | 2017-03-30 12:31:22 -0300 | 2017-03-31 12:25:05 -0300 |
| 53 | Nombre Cliente        | 2017-03-30 03:21:21 -0300 | 2017-03-31 12:25:05 -0300 |
| 67 | puntaje               | 2017-04-06 16:57:02 -0300 | 2017-04-06 16:57:02 -0300 |
+----+-----------------------+---------------------------+---------------------------+
6 rows in set

We need to clone the Form record and the associated FormFields, Fields records must not be cloned.

Problems appears because the cloned form can't be saved yet, the user has to change things like form name trough a simple_form (which displays the associated fields and their position/required options).

First try, deep cloning with FormField, it works for the :form_fields association but the :fields association is empty.

# Try 1
2.3.3 :041 > clone1 = form.deep_clone include: :form_fields
+----+------+------------+------------+
| id | name | created_at | updated_at |
+----+------+------------+------------+
|    | OK   |            |            |
+----+------+------------+------------+
1 row in set
2.3.3 :042 > clone1.form_fields
+----+---------+----------+----------+------------+------------+----------+
| id | form_id | field_id | position | created_at | updated_at | required |
+----+---------+----------+----------+------------+------------+----------+
|    |         | 45       | 20       |            |            | false    |
|    |         | 46       | 30       |            |            | false    |
|    |         | 47       | 40       |            |            | false    |
|    |         | 57       | 50       |            |            | false    |
|    |         | 53       | 10       |            |            | false    |
|    |         | 67       | 60       |            |            | true     |
+----+---------+----------+----------+------------+------------+----------+
6 rows in set
2.3.3 :043 > clone1.fields
 => #<ActiveRecord::Associations::CollectionProxy []> 

Trying to deep clone with Field ends with the form_fields association not properly cloned (null position and required attributes)

# Try 2
2.3.3 :045 > clone2 = form.deep_clone include: :fields
+----+------+------------+------------+
| id | name | created_at | updated_at |
+----+------+------------+------------+
|    | OK   |            |            |
+----+------+------------+------------+
1 row in set
2.3.3 :046 > clone2.form_fields
+----+---------+----------+----------+------------+------------+----------+
| id | form_id | field_id | position | created_at | updated_at | required |
+----+---------+----------+----------+------------+------------+----------+
|    |         | 45       |          |            |            | false    |
|    |         | 46       |          |            |            | false    |
|    |         | 47       |          |            |            | false    |
|    |         | 57       |          |            |            | false    |
|    |         | 53       |          |            |            | false    |
|    |         | 67       |          |            |            | false    |
+----+---------+----------+----------+------------+------------+----------+
6 rows in set
2.3.3 :047 > clone2.fields
+----+-----------------------+---------------------------+---------------------------+
| id | name                  | created_at                | updated_at                |
+----+-----------------------+---------------------------+---------------------------+
| 45 | RUT                   | 2017-03-29 16:11:18 -0300 | 2017-03-30 12:31:22 -0300 |
| 46 | Datos de Contacto     | 2017-03-29 16:12:11 -0300 | 2017-03-31 15:56:47 -0300 |
| 47 | Descripción Cliente   | 2017-03-29 16:15:18 -0300 | 2017-03-30 12:31:22 -0300 |
| 57 | Productos y Servicios | 2017-03-30 12:31:22 -0300 | 2017-03-31 12:25:05 -0300 |
| 53 | Nombre Cliente        | 2017-03-30 03:21:21 -0300 | 2017-03-31 12:25:05 -0300 |
| 67 | puntaje               | 2017-04-06 16:57:02 -0300 | 2017-04-06 16:57:02 -0300 |
+----+-----------------------+---------------------------+---------------------------+
6 rows in set

I tryed adding both of them in the include, but they end with duplicated entries in form_fields.

# Try 3
2.3.3 :048 > clone3 = form.deep_clone include: [:form_fields, :fields]
+----+------+------------+------------+
| id | name | created_at | updated_at |
+----+------+------------+------------+
|    | OK   |            |            |
+----+------+------------+------------+
1 row in set
2.3.3 :049 > clone3.form_fields
+----+---------+----------+----------+------------+------------+----------+
| id | form_id | field_id | position | created_at | updated_at | required |
+----+---------+----------+----------+------------+------------+----------+
|    |         | 45       | 20       |            |            | false    |
|    |         | 46       | 30       |            |            | false    |
|    |         | 47       | 40       |            |            | false    |
|    |         | 57       | 50       |            |            | false    |
|    |         | 53       | 10       |            |            | false    |
|    |         | 67       | 60       |            |            | true     |
|    |         | 45       |          |            |            | false    |
|    |         | 46       |          |            |            | false    |
|    |         | 47       |          |            |            | false    |
|    |         | 57       |          |            |            | false    |
|    |         | 53       |          |            |            | false    |
|    |         | 67       |          |            |            | false    |
+----+---------+----------+----------+------------+------------+----------+
12 rows in set
2.3.3 :050 > clone3.fields
+----+-----------------------+---------------------------+---------------------------+
| id | name                  | created_at                | updated_at                |
+----+-----------------------+---------------------------+---------------------------+
| 45 | RUT                   | 2017-03-29 16:11:18 -0300 | 2017-03-30 12:31:22 -0300 |
| 46 | Datos de Contacto     | 2017-03-29 16:12:11 -0300 | 2017-03-31 15:56:47 -0300 |
| 47 | Descripción Cliente   | 2017-03-29 16:15:18 -0300 | 2017-03-30 12:31:22 -0300 |
| 57 | Productos y Servicios | 2017-03-30 12:31:22 -0300 | 2017-03-31 12:25:05 -0300 |
| 53 | Nombre Cliente        | 2017-03-30 03:21:21 -0300 | 2017-03-31 12:25:05 -0300 |
| 67 | puntaje               | 2017-04-06 16:57:02 -0300 | 2017-04-06 16:57:02 -0300 |
+----+-----------------------+---------------------------+---------------------------+
6 rows in set

Is there any way to achieve this?

Thanks.

moiristo commented 7 years ago

I'd say it would be best to not use the fields association in this case, as you only want to dup the form_fields. So stick with clone1 = form.deep_clone include: :form_fields and render the fields in your form using clone1.form_fields.map(&:field). Would that work for you?

aldrinmartoq commented 7 years ago

@moiristo yes, something similar is what I'm doing but it means the has_many :through relationship is useless… It seems to be something related to rails rather than this gem.

Thank you.