nested form with polymorphic models

2019-06-25 23:33发布

问题:

I'm making an app with the following attributes, and I'm working on a creating a single form to be able to save a goal, a goal's tasks, a goal's milestones, and a milestone's tasks.

#app/models/goal.rb
  has_many :tasks, :as => :achievement
  has_many :milestones
  accepts_nested_attributes_for :tasks
  accepts_nested_attributes_for :milestones

#app/models/milestone.rb
  belongs_to :goal
  has_many :tasks, :as => :achievement

#app/models/task.rb
  belongs_to :achievement, :polymorphic => true

Whenever I save a goal with it's attributes, it seems the task models are getting confused as to what achievement_type they belong to, resulting in every milestone task just being listed as a goal task. My form, partials, and controller code are below.

form:

<%= nested_form_for @goal do |f| %>

  <%= render 'shared/error_messages', :object => f.object %>
  <%= render 'shared/goal_fields', :f => f %>

  <%= f.fields_for :milestones do |ff| %>
    <%= render 'shared/milestone_fields', :f => ff %>
  <% end %> 

  <%= f.fields_for :tasks do |ff| %>
    <%= render 'shared/task_fields', :f => ff %>
  <% end %>

  <%= f.link_to_add "Add Milestone", :milestones %>
  <%= f.link_to_add "Add Task", :tasks %>

  <%= f.submit %>

<% end %>

milestone_fields partial:

  <%= f.label :content, "Milestone" %>
  <%= f.text_field :content %>

  <%= f.fields_for :tasks do |ff| %>
    <%= render 'shared/task_fields', :f => ff %>
  <% end %>

  <%= f.link_to_remove "Remove milestone" %>
  <%= f.link_to_add "Add Milestone Task", :tasks %>

task_fields partial:

  <%= f.label :content, "Task" %>
  <%= f.text_field :content %>
  <%= f.link_to_remove "Remove Task" %>

goal controller:

def new
  @goal = current_user.goals.new
end

def create
  @user = current_user
  @goal = @user.goals.build(params[:goal])
  if @goal.save
    flash[:success] = "Goal created!"
    redirect_to goals_path 
  else
    render 'new'
  end 
end 

I tried adding @goal.milestones.build and @goal.tasks.build next to the f.fields_for code, which seems to have fixed it, but leads to other problems such as a blank edit form(no data is pre-populated) and the milestone and task fields showing up immediately instead of clicking a link to bring up a blank field. If you can't solve it, are there any sites where I can pay other coders to help solve a small problem like this? I'm desperate at this point.

回答1:

Your Milestone model needs the following line to be able to accept tasks_attributes:

# app/models/milestone.rb
accepts_nested_attributes_for :tasks

Everything else in the models look good. As for the fields_for form helper, passing build will create a new instance of the object specified, which will result in the blank edit form you describe. Try removing these builds if nested_form_for is going to handle building and appending these new form fields.

I recreated your environment, and when I post my form, I get the following params hash in the server log:

{"goal"=>{"milestones_attributes"=>{"0"=>{"content"=>"foo", "tasks_attributes"=>{"0"=>{"content"=>"bar"}}}}, "tasks_attributes"=>{"0"=>{"content"=>"baz"}}}}

This created two Task records, one of achievement_type 'Goal', and the other of achievement_type 'Milestone'

As for paying someone to do this work, http://www.rent-acoder.com/ is a website I have heard people say they have accepted work from in the past.I can't speak for the quality of the code, but you can post your work and see what bites you get.