[RUBY] Comment stocker simultanément des données dans un modèle associé à une forme imbriquée (Rails 6.0.0)

Conclusion Ajouter accepte_nested_attributes_for au modèle parent

Environnement de démonstration

・ Serveur Ubuntu Cloud9 ・ Rails 6.0.0 ・ Ruby 2.6.3p62 (révision 67580 du 16/04/2019) [x86_64-linux]

Conditions préalables

Supposons que vous ayez un modèle Parent et un modèle Kid avec des relations un-à-plusieurs comme ceci:

models/parent.rb


class Parent < ApplicationRecord
  has_many :kids, dependent: :destroy
end

models/kid.rb


class Kid < ApplicationRecord
  belongs_to :parent
end

Implémentation de formulaire imbriqué

Puisque les données du modèle enfant sont enregistrées en même temps que les données du modèle parent sont enregistrées, accepts_nested_attributes_for Vers le modèle Parent.

models/parent.rb


class Parent < ApplicationRecord
  has_many :kids, dependent: :destroy
  accepts_nested_attributes_for :kids
end

Cela vous permet d'utiliser des formulaires imbriqués qui vous permettent d'enregistrer les données associées dans un seul formulaire.

Ensuite, dans le contrôleur Parents du modèle parent, créez une instance vide qui reçoit les paramètres envoyés depuis la page de formulaire.

Il crée également une instance vide du modèle enfant associé. Aussi dans le paramètre fort pour recevoir les landaus du modèle enfant

kids_attributes: [:name, :age, :toy]


 Passe.


#### **`controllers/parents_controller.rb`**
```rb

class ParentsController < ApplicationController

#(Omis)
  
  def new
    @parent = Parent.new
    @parent.kids.build #Créer une instance vide du modèle enfant
  end
  
  def create
    @parent = Parent.new(parent_params)
    if @parent.save
      redirect_to root_url
    else
      render :new
    end
  end

#(Omission)
  
  private
  
    def parent_params
      #Vous permet de recevoir des paramètres pour les modèles enfants
      params.require(:parent).permit(
        :name, :age, kids_attributes: [:name, :age, :toy] 
      )
    end

end

erb:new.html.erb


<div class="container">
  <div class="col-sm-10 col-sm-offset-1">
    <h1 class="text-center">Inscription des parents</h1>
    <%= form_with(model: @parent, local: true) do |f| %>
      <div class="field form-group">
        <%= f.label :name %>
        <%= f.text_field :name, class: "form-control" %>
      </div>
      <div class="field form-group">
        <%= f.label :age %>
        <%= f.number_field :age, class: "form-control" %>
      </div>

      <!--Formulaire imbriqué pour recevoir des données pour les modèles enfants-->

      <%= f.fields_for :kids do |kf| %>
      <h1 class="text-center">Inscription des enfants</h1>
        <div class="field form-group">
          <%= kf.label :name %>
          <%= kf.text_field :name, class: "form-control" %>
        </div>
        <div class="field form-group">
          <%= kf.label :age %>
          <%= kf.number_field :age, class: "form-control" %>
        </div>
        <div class="field form-group">
          <%= kf.label :toy %>
          <%= kf.text_field :toy, class: "form-control" %>
        </div>
      <% end %>

      <div class="field form-group">
        <%= f.submit "Inscrivez-vous avec le contenu ci-dessus", class: "btn btn-primary btn-lg btn-block" %>
      </div>
    <% end %>
  </div>
</div>

C'est difficile à voir car il contient la classe Bootstrap, mais le `` f.fields_for '' ci-dessus est le formulaire qui reçoit les données du modèle enfant. ネストされたフォーム

Permet de sauvegarder les nouvelles données associées lors de la mise à jour des données

Bien qu'il s'agisse d'un formulaire de saisie pour les modèles enfants, en créant plusieurs instances vides, vous pouvez augmenter le nombre de champs de saisie sans augmenter la forme de vue elle-même. Par exemple, en modifiant le contrôleur Parents comme suit, un ensemble de formulaires d'entrée de modèle enfant peut être affiché lors de l'enregistrement nouvellement, et deux ensembles de formulaires d'entrée de modèle enfant peuvent être affichés lors de la mise à jour.

controllers/parents_controller.rb


class ParentsController < ApplicationController

#(Omission)

  def new
    @parent = Parent.new
    @parent.kids.build #Créer une instance vide du modèle enfant
  end
  
  def create
    @parent = Parent.new(parent_params)
    if @parent.save
      redirect_to root_url
    else
      render :new
    end
  end

#(Omission)

  def edit
    @parent = Parent.find(params[:id])
    @parent.kids.build #Créer une instance vide du modèle enfant
  end
  
  def update
    @parent = Parent.find(params[:id])
    if @parent.update(parent_params)
      redirect_to root_url
    else
      render :edit
    end
  end
  
  def destroy
    @parent = Parent.find(params[:id])
    @parent.destroy
    redirect_to root_url
  end
  
  private
  
    def parent_params
      params.require(:parent).permit(
        :name, :age, kids_attributes: [:name, :age, :toy]
      )
    end
    
end

En créant également une instance vide du modèle enfant dans l'action d'édition, les "données de modèle enfant enregistrées" + 1 formulaire d'entrée seront créés au moment de la mise à jour.

Cela rend plus facile d'augmenter le nombre de formulaires d'entrée que de les ajouter dynamiquement avec JS. (Le goulot d'étranglement est que le nombre est limité ...)

Si vous souhaitez ajouter plus de formulaires, vous pouvez créer plus d'instances vides.

@parent.kids.build


 De

#### **`n.times { @parent.kids.build }`**

Ce faisant, vous pouvez générer n formulaires d'entrée.

Empêche l'enregistrement des données vides si elles ne sont pas saisies

Cependant, en l'état, les données vides seront enregistrées si le formulaire ajouté n'est pas rempli. Pour éviter cela, passez le Proc suivant comme deuxième argument de accepts_nested_attributes_for ajouté au modèle Parent.

models/parent.rb


class Parent < ApplicationRecord
  has_many :kids, dependent: :destroy
  accepts_nested_attributes_for :kids, reject_if: lambda {|attributes| attributes['name'].blank?}
end

Dans le cas ci-dessus, si le nom du formulaire de saisie du modèle enfant est vide, tous les autres attributs (ici, âge, jouet) ne seront pas enregistrés même s'ils sont saisis.

Si vous ne souhaitez pas vous inscrire si le nom ou l'âge n'est pas entré, changez comme suit.

models/parent.rb


class Parent < ApplicationRecord
  has_many :kids, dependent: :destroy
  accepts_nested_attributes_for :kids, reject_if: lambda {|attributes| attributes['name'].blank? || attributes['age'].blank?}
end

En plus de ce qui précède, vous pouvez contrôler librement les valeurs stockées en modifiant la validation sur le modèle enfant.

En plus de cela, il peut y avoir des cas où vous souhaitez supprimer uniquement les données du modèle enfant associé, mais pour plus de détails, voir «Action View Form Helper» dans le Guide Rails. Ce sera utile.

Épilogue

Je suis Tatsuron, un débutant qui apprend actuellement Ruby on Rails. J'ai publié des articles sur les fonctionnalités bloquées pendant plusieurs jours lors de la création de ma propre application. Si vous avez des erreurs ou des conseils, veuillez commenter.

Recommended Posts

Comment stocker simultanément des données dans un modèle associé à une forme imbriquée (Rails 6.0.0)
Comment renommer un modèle avec des contraintes de clé externes dans Rails
Comment insérer une vidéo dans Rails
Comment obtenir la valeur de boolean avec jQuery sous forme simple de rails
[Rails] Je souhaite envoyer des données de différents modèles dans un formulaire
Comment implémenter une fonctionnalité similaire dans Rails
Comment créer facilement un pull-down avec des rails
Comment créer une combinaison unique de données dans la table intermédiaire des rails
Comment effacer toutes les données d'une table particulière
Comment implémenter une fonctionnalité intéressante dans Ajax avec Rails
Comment supprimer un objet new_record construit avec Rails
Comment générer manuellement un JWT avec Knock in Rails
Comment créer un URI de données (base64) en Java
Comment écrire une recherche de comparaison de dates dans Rails
Comment interroger Array dans jsonb avec Rails + postgres
[Rails 6] Comment définir une image d'arrière-plan dans Rails [CSS]
[Rails] Comment charger JavaScript dans une vue spécifique
Comment gérer les erreurs dans Rails? Impossible de trouver un runtime JavaScript.
Comment stocker des chaînes de ArrayList à String en Java (personnel)
Comment afficher des graphiques dans Ruby on Rails (LazyHighChart)
Comment ajouter les mêmes index dans un tableau imbriqué
Mappage à une classe avec un objet de valeur dans How to My Batis
Comment simuler le téléchargement de formulaires post-objet vers OSS en Java
Comment configurer un proxy avec authentification dans Feign
Comment écrire dans la classe Model lorsque vous souhaitez enregistrer des données binaires dans DB avec PlayFramework
Implémenter un formulaire de contact dans Rails
Comment installer jQuery dans Rails 6
Comment installer Swiper in Rails
Comment créer un fichier jar sans dépendances dans Maven
[Rails 6] Comment créer un écran de saisie de formulaire dynamique à l'aide de cocoon
[rails] Comment afficher les informations parent dans la vue enfant dans des relations imbriquées
Comment supprimer de grandes quantités de données dans Rails et problèmes
Comment stocker les informations saisies dans la zone de texte dans une variable de la méthode
Comment implémenter la fonctionnalité de recherche dans Rails
Comment changer le nom de l'application dans les rails
Comment mettre en œuvre un diaporama en utilisant Slick in Rails (un par un et plusieurs par un)
[Pour les débutants] Je souhaite saisir automatiquement des données pré-enregistrées dans le formulaire de saisie avec une commande de sélection.
Comment créer une requête à l'aide de variables dans GraphQL [Utilisation de Ruby on Rails]
[Mémo personnel] Comment interagir avec le générateur de nombres aléatoires en Java
Comment utiliser MySQL dans le didacticiel Rails
Comment mettre à jour les modifications utilisateur dans Rails Devise sans entrer de mot de passe
Comment créer un environnement de développement Ruby on Rails avec Docker (Rails 6.x)
[Rails] Comment obtenir les informations sur l'utilisateur actuellement connecté avec devise
[rails] Comment configurer le routage dans les ressources
[rails] Comment créer un modèle partiel
Comment implémenter la fonctionnalité de classement dans Rails
Comment supprimer des données avec une clé externe
Comment déboguer le traitement dans le modèle Ruby on Rails avec juste la console
Comment créer un environnement de développement Ruby on Rails avec Docker (Rails 5.x)