J'ai un problème pour gérer un has_many: par association à l'aide d'un formulaire. Ce que je ne veux pas faire, c'est éditer les attributs du modèle associé dont il existe une pléthore d'informations, plutôt, je veux gérer l'association SEULEMENT. Je comprends que je pourrais le faire en manipulant les paramètres de formulaire passés à mon action et en créant les relations manuellement, mais je préférerais suivre la méthode Rails, si cela est possible).
Une chose intéressante à propos de mon cas est que cette has_many: through association est en fait sur un modèle que j'enregistre déjà en utilisant accept_nested_attributes_for
Voici mes modèles: objectifs, jalons et programmes.
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
Maintenant, dans ma vue de modification d'objectif, je dois pouvoir ajouter et supprimer des jalons, et pour ces jalons, je dois pouvoir ajouter et supprimer des associations de programmes. Ceci est le code de mon formulaire.
<%= 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 %>
Dans mon contrôleur, j'ai
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
Ce formulaire doit être comme une feuille de calcul où vous pouvez apporter des modifications et enregistrer uniquement vos modifications une fois que vous avez cliqué sur enregistrer à la fin, donc je ne pense pas que des gemmes telles que cocoon ou nested_forms vous aideront.
Mon code fonctionne parfaitement jusqu'à présent pour gérer mes objectifs associés et leurs attributs. Mais maintenant, je veux pouvoir gérer la liste des programmes associés à ces jalons.
J'ai essayé d'utiliser accept_nested_attributes_for mais ce n'est pas exactement ce que je veux parce que je n'aime pas éditer les attributs imbriqués du modèle, les attributs du programme doivent rester statiques.
J'ai pensé que je pourrais avoir quelque chose comme ça dans ma forme pour chaque programme pour construire les associations:
<input type="hidden" name="goal[milestones_attributes][1][program_ids][1]" >
Mais cela ne fonctionne pas non plus (bien sûr, j'ai ajouté: program_ids à mes paramètres en liste blanche). Existe-t-il une méthode magique Rails que je dois ajouter à mon contrôleur?
Qu'est-ce que j'oublie ici?
Merci d'avance!
Lorsque vous utilisez un has_many :through
relation, vous devez passer le nested_attributes
à travers les différents modèles, comme ceci:
Modèles
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
Contrôleur
#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
Formulaire
#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 %>
J'apprécie que ce ne soit pas exactement ce que vous cherchez, mais je n'ai pas lu toute votre prose. Je viens de comprendre que vous aviez besoin d'aide pour passer nested_attributes
à travers un has_many :through
relation