I am relatively new to rails, but I have successfully used nested attributes in strong params and arrays in strong params. However, I'm really stuck. I am creating a form to update a Model with two later nesting:
Project > Milestones > Tasks.
Instead of the usual model of having a user create the tasks & milestones, the tasks and milestones are already created based on the kind of project using another set of nested attributes.
Template > MilestoneTemplate > TaskTemplate.
When I try to submit my form....I get this:
ActiveModel::ForbiddenAttributesError
These are my models:
template.rb
# == Schema Information
#
# Table name: templates
#
# id :integer not null, primary key
# name :string
# created_at :datetime not null
# updated_at :datetime not null
#
class Template < ActiveRecord::Base
has_many :milestone_templates
has_many :projects
validates_presence_of :name, message: "Template must have a name"
validates_uniqueness_of :name, message: "Looks like you\'ve already added this Template."
end
project.rb
# == Schema Information
#
# Table name: projects
#
# id :integer not null, primary key
# template_id :integer
# name :string
# created_at :datetime not null
# updated_at :datetime not null
#
class Project < ActiveRecord::Base
belongs_to :template
has_many :milestones
has_many :tasks
accepts_nested_attributes_for :tasks, allow_destroy: true
accepts_nested_attributes_for :milestones, allow_destroy: true
validates_presence_of :name, message: "Project must have a name"
validates_uniqueness_of :name, message: "Looks like you\'ve already added this Project."
validates :template_id, presence: true
end
milestone_template.rb
# == Schema Information
#
# Table name: milestone_templates
#
# id :integer not null, primary key
# template_id :integer
# name :string
# created_at :datetime not null
# updated_at :datetime not null
#
class MilestoneTemplate < ActiveRecord::Base
belongs_to :template
has_many :task_templates, dependent: :destroy
validates_uniqueness_of :name, scope: :template_id, message: "Looks like you\'ve already added this Milestone Template."
validates_presence_of :name, message: "Milestone Template must have a name"
accepts_nested_attributes_for :task_templates, allow_destroy: true
end
task_template.rb
# == Schema Information
#
# Table name: task_templates
#
# id :integer not null, primary key
# template_id :integer
# milestone_template_id :integer
# name :string
# created_at :datetime not null
# updated_at :datetime not null
#
class TaskTemplate < ActiveRecord::Base
belongs_to :milestone_template, inverse_of: :task_templates
validates_uniqueness_of :name, scope: :milestone_template_id, message: "Looks like you\'ve already added this Task Template."
validates_presence_of :name, message: " Task Template must have a name"
end
milestone.rb
# == Schema Information
#
# Table name: milestones
#
# id :integer not null, primary key
# project_id :integer
# milestone_template_id :integer
# name :string
# created_at :datetime not null
# updated_at :datetime not null
#
class Milestone < ActiveRecord::Base
belongs_to :project
belongs_to :milestone_template
has_many :tasks, dependent: :destroy
validates_presence_of :name, message: "Enter the Milestone Name."
validates_uniqueness_of :name, scope: :project_id, message: "Looks like you\'ve already added this Milestone."
accepts_nested_attributes_for :tasks, allow_destroy: true
end
task.rb
# == Schema Information
#
# Table name: tasks
#
# id :integer not null, primary key
# project_id :integer
# milestone_id :integer
# task_template_id :integer
# name :string
# created_at :datetime not null
# updated_at :datetime not null
#
class Task < ActiveRecord::Base
belongs_to :project
belongs_to :milestone
belongs_to :task_template
validates_uniqueness_of :name, scope: :project_id, message: "Looks like you\'ve already added this Task to this Project."
validates_presence_of :name, message: " Task must have a name"
end
_form.html.erb
<%= form_for @project do |f| %>
<% @milestones_templates.each_with_index do |milestone, index| %>
<br>
<%= f.fields_for :milestones, index: index do |fm| %>
<%= fm.hidden_field :name, value: milestone.name %>
<!-- Create a checkbox to add the milestone_id to the project -->
<%= fm.label milestone.name %>
<%= fm.check_box :milestone_template_id, value: milestone.id %>
<br>
<% milestone.task_templates.each_with_index do |task, another_index| %>
<%= fm.fields_for :tasks, index: another_index do |ft| %>
<!-- Create a checkbox for each task in the milestone -->
<%= ft.label task.name %>
<%= fm.hidden_field :name, value: task.name %>
<%= ft.check_box :task_template_id, value: task.id %>
<% end %>
<% end %>
<br>
<% end %>
<% end %>
<br>
<%= f.submit %>
<% end %>
projects_controller.rb
class ProjectsController < ApplicationController
def new_milestones
@project.milestones.build
@project.tasks.build
@milestones_templates = MilestoneTemplate.where(template_id: @project.template_id)
end
def update
respond_to do |format|
result = ProjectUpdater.perform(@project, project_params, params) == true
if result == true
format.html { redirect_to @project, notice: 'Project was successfully updated.' }
format.json { render :show, status: :ok, location: @project }
else
@project = result
format.html { render :edit }
format.json { render json: @project.errors, status: :unprocessable_entity }
end
end
end
def project_params
params.require(:project).permit(:id, :name, milestones_attributes: [:name, :id, :project_id, {:milestone_template_ids =>[]}, :_destroy, tasks_attributes: [:id, :project_id, :name, {:task_template_ids =>[]}, :_destroy ] ] )
end
lib/project_updater.rb**This is very new for me...so mistakes might be here.
class ProjectUpdater
def self.perform(project, params, project_params)
milestones = params[:milestones]
if project.update_attributes(project_params)
return true
else
return project
end
end
end
Aucun commentaire:
Enregistrer un commentaire