Подтвердить что ты не робот

Rails 4 вложенных атрибутов и has_many: через associaton в форме

У меня возникла проблема с управлением 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

Теперь в моем представлении редактирования цели мне нужно иметь возможность добавлять и удалять контрольные точки, и для этих этапов мне нужно иметь возможность добавлять и удалять ассоциации программ. Это код для моей формы.

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

В моем контроллере у меня есть

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

Эта форма должна быть похожа на рабочий лист, где вы можете вносить изменения и сохранять свои изменения только после того, как вы нажмете "Сохранить" в конце, поэтому я не верю, что камни, такие как кокон или вложенные_формы, помогут.

Мой код отлично работает до сих пор для управления моими целями, связанными с вехами и их атрибутами. Но теперь я хочу иметь возможность управлять списком программ, связанных с этими вехами.

Я попытался использовать accepts_nested_attributes_for, но это не совсем то, что я хочу, потому что я не хочу редактировать вложенные атрибуты модели, атрибуты программы остаются статическими.

Я думал, что мог бы иметь что-то вроде этого в моей форме для каждой программы для создания ассоциаций:

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

Но это тоже не сработает (конечно, я добавил: program_ids к моим параметрам, перечисленным в белом списке). Есть ли метод волшебных рельсов, который мне нужно добавить к моему контроллеру?

Что мне здесь не хватает?

Спасибо заранее!

4b9b3361

Ответ 1

При использовании отношения 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

контроллер

#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

Форма

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

Я ценю, что это может быть не совсем то, что вы ищете, но tbh я не читал всю вашу прозу. Я только что собрал вам необходимую помощь, пропустив nested_attributes через связь has_many :through