Sunday, March 12, 2017

How to create a complex Nested -> Belongs To object?

Leave a Comment

I'm building a form where a user should be able to create a template with fields. However they should also be able to create an optional Collection which belongs_to each Field at the same time.

So far it looks like this:

Tables

templates: id, name template_fields: id, template_id, collection_id, field_name collections: id, name collection_values: id, collection_id, value 

Models

Template

class Template < ActiveRecord::Base   has_many :template_fields   accepts_nested_attributes_for :template_fields end 

Template Fields

class TemplateField < ActiveRecord::Base   belongs_to :template   belongs_to :collection end 

Collection

class Collection < ActiveRecord::Base   has_many :collection_values end 

CollectionValue

class CollectionValue < ActiveRecord::Base   belongs_to :collection end 

How can I create these objects? How do I go about this in the controller?

The only way I can think of is to create it as a nested association (even though Collection isn't really a nested attribute) or create the Collections before the Templates, and somehow link each Field to each Collection that was created.

Controller

def create   @template = Template.new(template_params)   if @template.save     flash[:notice] = "Template successfully created."     flash[:color]= "valid"     redirect_to templates_path   else     flash[:notice] = "Form is invalid"     flash[:color]= "invalid"     render :new   end end  def template_params   params.require(:template).permit(:id,:name, template_fields_attributes: [:id, :template_id, :field_name, :collection_id, collection_values_attributes: [:value] ]) end 

3 Answers

Answers 1

I think you need to add these kind of relationships to your model has_many :through and has_one :through to relate collection and collection_values to template and then modify your template.rb to include:

has_one :collection, through: :template_fields 

The line above assumes that one template has only one collection

has_many :collection_values, through: :collection accepts_nested_attributes_for :template_fields, :collection, :collection_values 

You also need to modify the template_params in your controller to include collection_attributes and collection_values_attributes

Answers 2

For requirements given you may have:

class CollectionValue < ActiveRecord::Base   belongs_to :collection end  class Collection < ActiveRecord::Base   has_many :collection_values   accepts_nested_attributes_for :collection_values end  class TemplateField < ActiveRecord::Base   belongs_to :template   belongs_to :collection   accepts_nested_attributes_for :collection end  class Template < ActiveRecord::Base   has_many :template_fields   accepts_nested_attributes_for :template_fields end 

That would make following code work:

Template.create name: 'template_name',   template_fields_attributes: [     {name: 'field_name', collection_attributes:       {name: 'collection_name', collection_values_attributes: [         {name: 'col_value_1'},         {name: 'col_value_2'}       ]}     }   ] 

You may try it in rails console. This example would create all of records as it doesn't include any IDs. It would work same way in TemplateController#create

It's better for you to read and understand accepts_nested_attributes_for

Answers 3

This can be done - however it required manipulating the params to a large extent and was very convoluted/tightly coupled. Have opted to use AJAX to create a collection before the form is saved.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment