Updating deeply nested models with rails and angularjs -


i have researched question much, no solution nested models. have come following fix, wondering if there better way.

i've tried cut down simple can make explain issue , solution.

the issue there exist following activerecord models in rails:

deeply nested object tree

class template has_many :sections, dependent: :destroy accepts_nested_attributes_for :sections has_many :columns, through: :sections, dependent: :destroy has_many :fields, through: :columns, dependent: :destroy  class section belongs_to :template has_many :columns, dependent: :destroy accepts_nested_attributes_for :columns  class column belongs_to :section has_many :fields, dependent: :destroy accepts_nested_attributes_for :fields  class field belongs_to :column‏ 

and in angular, goal send single ngresource $resource call 'templates/:id' , update entire chain of children. (each piece of chain created prior, in template creation process. need unified update occurs when template finalized.)

### classfactory.coffee ### # # create connection api # ...     return $resource('api/:class/:id', { format: 'json' }, {...}) # ...  ### edittemplatecontroller.coffee ### # # create angular template resource, save it, , redirect editing view # ...     $scope.template = new classfactory({class: 'templates'})     $scope.template.$save({class: 'templates'}, (res)->         $location.path('templates/'+res.id+'/edit')     ) # # update angular object # ...     $scope.savetemplate = ->         $scope.template.$update({class: 'templates', id: $scope.template.id}) #...  ### templates_controller.rb ### # # create single db interaction deliberately declared parameters , nested *_attributes parameters # ...   def update     params[:template][:sections_attributes] = params[:sections]     params[:template][:sections_attributes].each |paramsection|       paramsection[:columns_attributes] = paramsection[:columns]       paramsection[:columns_attributes].each |paramcolumn|         paramcolumn[:fields_attributes] = paramcolumn[:fields]       end     end     template = current_user.templates.find(params[:id])     template.update_attributes(allowed_params)     head :no_content   end    private     def allowed_params       params.require(:template).permit(         :name, sections_attributes: [           :id, :name, columns_attributes: [             :id, :fields_attributes: [               :id, :name, :value             ]           ]         ]     end # ... 

as far have worked out, fix declare *_attributes shown above:

params[:template][:sections_attributes] = params[:sections] 

because of angular's inability send format of parameters rails looking for.

this feels hacky solution. there no better way handle nested rails models while using angularjs?

as discussed in this rails github issue, acknowledged issue way angularjs $resource sends parameters, versus rails expects when using accepts_nested_attributes_for.

per issue, , until resolved in rails fix, here can changed in above example separate parts bit more manageable:

add rails controller model uses accepts_nested_attributes_for:

class modelcontroller < applicationcontroller   nested_attributes_names = model.nested_attributes_options.keys.map |key|      key.to_s.concat('_attributes').to_sym   end    wrap_parameters include: model.attribute_names + nested_attributes_names    # ... end 

clean rails controller update method moving nested *_attributes declarations angularjs controller before saving model:

$scope.savetemplate = ->     $scope.template.sections_attributes = $scope.template.sections     $scope.template.sections_attributes.foreach((section)->         section.columns_attributes = section.columns         section.columns_attributes.foreach((column)->             column.fields_attributes = column.fields         )     )     $scope.template.$update({class: 'templates', id: $scope.template.id}) 

it's not pretty that's seemingly can done specific issue until it's patched.


Comments