Ruby-on-rails Rails 4 嵌套属性和 has_many :通过表单中的关联

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21983131/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 23:23:58  来源:igfitidea点击:

Rails 4 nested attributes and has_many :through associaton in a form

ruby-on-railsformsactiverecordruby-on-rails-4

提问by Cameron

I am having an issue managing a has_many :through association using a form. What I DON'T want to do is edit the attributes of the associated model of which there is a plethora of information out there, rather, I want to manage the association ONLY. I understand I could do this by manipulating the form parameters passed to my action and build the relationships manually, but I would prefer to go the Rails way, if that is possible.

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

One interesting thing about my case is that this has_many :through association is actually on a Model which I am already saving using accepts_nested_attributes_for

关于我的案例的一件有趣的事情是,这个 has_many :through 关联实际上是在我已经使用 accepts_nested_attributes_for 保存的模型上

Here are my models: Goals, Milestones and Programs.

这是我的模型:目标、里程碑和计划。

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

Now in my Goal edit view, I need to be able to add and remove milestones, and for those milestones I need to be able to add and remove program associations. This is the code for my form.

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

<%= 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 %>

In my controller, I have

在我的控制器中,我有

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

This form needs to be like a worksheet where you can make changes and only save your changes once you click save at the end, so I don't believe gems such as cocoon or nested_forms will help.

此表单需要像工作表一样,您可以在其中进行更改,并且只有在最后单击“保存”后才保存更改,因此我不相信诸如 cocoon 或nested_forms 之类的宝石会有所帮助。

My code works perfectly so far for managing my Goals associated Milestones and their attributes. But now I want to be able to manage the list of Programs associated to those Milestones.

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

I have tried using accepts_nested_attributes_for but that is not exactly what I want because I don't care to edit the nested attributes of the model, the Program attributes are to remain static.

我曾尝试使用 accepts_nested_attributes_for 但这并不是我想要的,因为我不关心编辑模型的嵌套属性,程序属性将保持静态。

I thought I might be able to have something like this in my form for each program to build the associations:

我想我可以在我的表单中为每个程序提供类似的东西来建立关联:

<input type="hidden" name="goal[milestones_attributes][1][program_ids][1]" >

But that doesn't work either (of course I've added :program_ids to my white-listed parameters). Is there a magic rails method I need to add to my controller?

但这也不起作用(当然,我已将 :program_ids 添加到我的白名单参数中)。是否有我需要添加到我的控制器的魔法 rails 方法?

What am I missing here?

我在这里缺少什么?

Thanks in advance!

提前致谢!

回答by Richard Peck

When employing a has_many :throughrelationship, you need to pass the nested_attributesthrough the different models, like this:

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

Models

楷模

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

Controller

控制器

#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

Form

形式

#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 %>

I appreciate this might not be exactly what you're looking for, but tbh I didn't read all your prose. I just gathered you needed help passing nested_attributesthrough a has_many :throughrelationship

我很欣赏这可能不是您正在寻找的内容,但是我没有阅读您所有的散文。我刚刚收集到你nested_attributes在一段has_many :through关系中需要帮助