En utilisant accepts_nested_attributes_for avec une association de belongs_to, et en utilisant le comportement find_or_create_by_attr
-
24-10-2019 - |
Question
Je construis une application Rails qui permet à un utilisateur de créer un objet qui fait référence à plusieurs autres modèles, les créer si elles n'existent pas, et juste associer à ceux qui existent déjà:
# app/models/upload.rb
class Upload < AR:B
belongs_to :user
belongs_to :observed_property
belongs_to :sensor
accepts_nested_attributes_for :observed_property, :sensor
validates_presence_of :observed_property, :sensor
end
(Les associations de capteur et observed_property ne sont qu'un sens, il n'y a pas de retour has_many.)
Le contrôleur est spécial, rien que sept norme RESTful, et je pense qu'il serait possible de le faire correctement tout en gardant la plupart de la logique dans le modèle.
Au lieu d'avoir le remplissage de l'utilisateur de multiples formes différentes et ensuite référencer ces objets séparément, j'ai tenté d'utiliser accepts_nested_attributes_for
pour les incorporer dans la forme Upload
utilisant fields_for
:
# app/views/uploads/new.html.erb
<% form_for @upload, :url => user_uploads_path(@user) do |f| %>
<%= f.error_messages %>
<% f.fields_for :observed_property do |builder| %>
<fieldset>
<legend>Observed Property</legend>
<p><%= builder.label :_id, "Observed Property ID" %><br />
<%= builder.text_field :_id %></p>
<p><%= builder.label :description %><br />
<%= builder.text_area :description, :rows => 5 %></p>
</fieldset>
<% end %>
<% f.fields_for :sensor do |builder| %>
<fieldset>
<legend>Sensor</legend>
<p><%= builder.label :_id, "Sensor ID" %><br />
<%= builder.text_field :_id %></p>
<p><%= builder.label :description %><br />
<%= builder.text_area :description, :rows => 5 %></p>
</fieldset>
<% end %>
<%= f.submit "Submit", :class => "button" %>
<% end %>
Cela ne fonctionne pas, car aucun formulaire est affiché pour la fields_for
. J'ai essayé d'appliquer ce qui a été mentionné dans cette réponse , mais le modèle échouerait sauver, en citant les associations manquantes.
J'ai essayé quelques choses hackish telles que les méthodes de remplaçant sensor=
et observed_property=
et la mise en cache des hash pour before_save
, mais qui ne se sent pas vraiment comme la bonne façon de faire les choses.
La solution
J'ai fini avec la solution suivante, et il ne semble travailler. J'ai créé un point essentiel pour maintenir la solution avec une spécification correspondante pour définir le comportement que je cherchais.