Rails 4嵌套属性和has_many:通过表单中的associaton

Cam*_*ron 20 forms activerecord ruby-on-rails ruby-on-rails-4

我在管理has_many时遇到问题:通过使用表单进行关联.我不想做的是编辑相关模型的属性,其中有大量信息,而我只想管理关联.我理解我可以通过操作传递给我的操作的表单参数并手动构建关系来做到这一点,但我更愿意采用Rails方式,如果可能的话.

关于我的一个有趣的事情就是这个has_many:通过关联实际上是一个我已经使用accepts_nested_attributes_for保存的模型

以下是我的模型:目标,里程碑和程序.

class Goal < ActiveRecord::Base
  has_many :milestones, inverse_of: :goal, dependent: :destroy
  accepts_nested_attributes_for :milestones, :allow_destroy => true
end

class Milestone < ActiveRecord::Base
  belongs_to :goal, inverse_of: :milestones

  has_many :milestone_programs
  has_many :programs, :through => :milestone_programs
end

class Program < ActiveRecord::Base
end
Run Code Online (Sandbox Code Playgroud)

现在,在我的目标编辑视图中,我需要能够添加和删除里程碑,对于那些里程碑,我需要能够添加和删除程序关联.这是我表单的代码.

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

  <%= f.fields_for :milestones do |f_milestone| %>

    <%= f.hidden_field :id, :value => f.object.id %>
    <%= f.hidden_field :name, :value => f.object.name %>
    <a href="javascript:void(0)" class="milestone-remove">- remove</a>

    <ul>
      <%= f.fields_for :programs do |f_prog| %>
        <li>
          <%= f_prog.object.name %>
          <a href="javascript:void(0)" class="program-remove">- remove</a>
        </li>
      <% end %>
    </ul>

  <% end %>

  <%= f.submit 'Save' %>

<% end %>
Run Code Online (Sandbox Code Playgroud)

在我的控制器中,我有

class GoalsController < ApplicationController

    # PATCH/PUT /goals/:id
    def update
      if @goal.update(goal_params)
        redirect_to @goal
      end
    end

    def goal_params
      params.require(:goal).permit(:name, :milestones_attributes => [ :id, :name, :_destroy ])
    end

end
Run Code Online (Sandbox Code Playgroud)

此表单必须像工作表,您可以在其中进行更改,并且只在最后单击保存时保存更改,因此我不相信诸如cocoon或nested_forms之类的gem会有所帮助.

到目前为止,我的代码完美地用于管理我的目标相关里程碑及其属性.但现在我希望能够管理与这些里程碑相关的程序列表.

我尝试过使用accepts_nested_attributes_for,但这并不是我想要的,因为我不关心编辑模型的嵌套属性,Program属性要保持静态.

我想我可能会在每个程序的表单中都有这样的东西来构建关联:

<input type="hidden" name="goal[milestones_attributes][1][program_ids][1]" >
Run Code Online (Sandbox Code Playgroud)

但这也不起作用(当然我已经添加了:program_ids到我列入白名单的参数).我需要添加到控制器中的魔术轨道方法吗?

我在这里错过了什么?

提前致谢!

Ric*_*eck 34

在使用has_many :through关系时,您需要nested_attributes通过不同的模型,如下所示:

楷模

class Goal < ActiveRecord::Base
  has_many :milestones, inverse_of: :goal, dependent: :destroy
  accepts_nested_attributes_for :milestones, :allow_destroy => true

  def self.build
      goal = self.new
      goal.milestones.build.milestone_programs.build_program
  end
end

class Milestone < ActiveRecord::Base
  belongs_to :goal, inverse_of: :milestones

  has_many :milestone_programs
  has_many :programs, through: :milestone_programs

  accepts_nested_attributes_for :milestone_programs
end

class MilestoneProgram < ActiveRecord::Base
    belongs_to :milestone
    belongs_to :program

    accepts_nested_attributes_for :program
end

class Program
    has_many :milestone_programs
    has_many :milestones, through: :milestone_programs
end
Run Code Online (Sandbox Code Playgroud)

调节器

#app/controllers/goals_controller.rb
def new
    @goal = Goal.build
end

def create
    @goal = Goal.new(goal_params)
    @goal.save
end

private

def goal_params
    params.require(:goal).permit(milestones_attributes: [milestone_programs_attributes: [program_attributes:[]]])
end
Run Code Online (Sandbox Code Playgroud)

形成

#app/views/goals/new.html.erb
<%= form_for @goal do |f| %>
   <%= f.fields_for :milestones do |m| %>
      <%= m.fields_for :milestone_programs do |mp| %>
          <%= mp.fields_for :program do |p| %>
               <%= p.text_field :name %>
          <% end %>
      <% end %>
   <% end %>
   <%= f.submit %>
<% end %>
Run Code Online (Sandbox Code Playgroud)

我很欣赏这可能不是你想要的,但是我没有阅读你所有的散文.我刚刚收集了你需要的帮助,nested_attributes通过一段has_many :through感情

  • @RichPeck我想你可能会错过你的`self.build`方法中的'build',所以它应该是`goal.milestones.build.milestone_programs.build.build_program` (2认同)