How do I add user defined custom fields to a model?

988 views Asked by At

In my blog application, I have a post model (name:string, body:text). I want to allow the user to define a custom_field (the model has name:string). This causes the post form to contain a text_field for that custom_field, and the value of that field should be returned as a param from create or update. The actual data returned is of model custom_field_instance (value:string custom_field:references post:references)

For example, if a user created a custom field with name author, and another custom field with name email then I want the post form to display an author and email text fields, and two custom field instances to be returned with the params (one for author, one for email).

The custom fields show up fine in the form, no problem. The params also look fine when there is a single custom field.

The problem is that only one custom field's params are sent in the params. If there are multiple fields, then only the last one's data is sent.

Suppose I have an author and email custom field, and in the new post form, I set name as 'John Doe' and email as '[email protected]', here is what I get in the params (only one custom field instance, the email one, which is the last one):

Parameters: 
{..., "post"=>{"title"=>"post2", ...}, 
  "custom_field_instances"=>
     {"value"=>"[email protected]", "custom_field_id"=>[email_custom_field_id]}, 
"commit"=>"Create Post"}

Here is what I expect to see in the params (both custom field instances :

Parameters: 
{..., "post"=>{"title"=>"post2", ...}, 
  "custom_field_instances"=> 
     {"value"=>"John Doe", "custom_field_id"=>[author_custom_field_id]},   
     {"value"=>"[email protected]", "custom_field_id"=>[email_custom_field_id]}, 
"commit"=>"Create Post"}

Here is the code that I have so far:

posts_controller.rb:

def new
  @post = Post.new
  @custom_fields = CustomField.all
end

views/posts/new.html.erb:

<%= form_for @post,... %>
...
<% @custom_fields.each do |custom_field| %>
    <% @custom_field_instance = CustomFieldInstance.new %>
    <%= fields_for :custom_field_instances, @custom_field_instance do |custom_field_instance_fields| %>
        <%= custom_field_instance_fields.label custom_field.name %>
        <%= custom_field_instance_fields.text_field :value %>       
        <%= custom_field_instance_fields.hidden_field :custom_field_id, value: custom_field.id %>
    <% end %> <!-- end of fields_for block  -->
  <% end %> <!-- end of custom_fields.each loop  -->
...
<% end %> <!-- end of form_for block  -->

I have also tried without the @custom_field_instance where the fields_for line becomes <%= fields_for :custom_field_instances do |custom_field_instance_fields| %>, but it doesn't change anything (still the last custom field instance is the only one sent in the params).

Update 1: I also tried using accepts_nested_attributes_for, but then the view did not show the custom field text fields, since it seems like nested_attributes are only used for existing instances of the associated model. The changes are:

To the above code, I added accepts_nested_attributes_for :custom_field_instances to item_instance.rb, and in the view code above, replaced fields_for ... with post_form.fields_for ...

1

There are 1 answers

7
Nithin On BEST ANSWER

Make it as an Array

Not tested.

try1:

<%= custom_field_instance_fields.text_field, name: 'value[]' %>

or

<%= custom_field_instance_fields.text_field, 'value[]' %>

same for hidden field.


try2: ( worked for OP )

use {:multiple => true}


try3:

serialize :name, Array

in your CustomFieldInstance model