En essayant d'introduire une sélection déroulante dans form_with et en l'implémentant, il y avait des endroits où j'ai répété des essais et des erreurs, donc je vais le laisser comme un rappel.
・ Rubis 2.6.5 ・ Rails 6.0.3
Il y a une table de magasin pour enregistrer les informations du restaurant. Il existe une table de station qui contient les données de station sur la ligne Yamate sous forme de liste. Les deux tables ont une relation plusieurs à plusieurs et forment une association via une table intermédiaire (table shop_station).
Je souhaite implémenter les fonctions suivantes. ** ① Lors de la création de données de magasin, je souhaite sélectionner et enregistrer la station la plus proche dans le menu déroulant. ** ** ** ② L'enregistrement de la station la plus proche est facultatif et ne doit pas être enregistré. Vous pouvez enregistrer jusqu'à 2 stations. ** ** ** ③ Naturellement, je souhaite enregistrer toutes les stations les plus proches en même temps en soumettant le formulaire une fois. ** **
Je laisserai la procédure de montage ci-dessus pour rappel.
Eh bien, j'écrirai la procédure ci-dessous.
Cette fois, nous implémenterons le formulaire dans la nouvelle action du contrôleur de boutique. Je vais d'abord extraire et écrire le code.
Controller
shops_controller.rb
before_action :set_select_lists, only: [:new]
def new
@shop = Shop.new
end
private
def set_select_lists
@stations = Station.all.map {|station| [station.name, station.id] }
end
View
haml:new.html.haml
.shop-wrapper
= form_with model: [@owner, @shop], html: {class: "shopform"}, local: true do |f|
-#Omission(L'indentation est appropriée pour mettre en évidence la syntaxe. Excusez-moi. Indentation selon la notation haml)
= f.select :station_ids, @stations,{},{class: "select"}
= f.select :station_ids, @stations,{},{class: "select"}
* En enregistrant la station la plus proche, elle sera affichée dans la recherche de désignation de station.
L'explication de chacun est la suivante.
Controller @stations crée les données qui serviront de base à ce choix. Ce qui suit est une explication approximative.
Station.all Toutes les données de la table Station
Station.all.map {~} Pour chaque donnée (enregistrement) de la table Station toutes les données, traiter selon {}
Station.all.map {|station| [station.name, station.id]} Génère un hachage avec chaque enregistrement comme station, station.name (valeur dans la colonne name de chaque enregistrement) comme clé et station.id (valeur dans la colonne id) comme valeur.
View
= f.select :station_ids, @stations,{},{class: "select"}
Envoyez des données avec form_with. Créez un menu déroulant avec f.select. Lors de l'envoi de données, envoyez-les avec la clé: station_ids. Les choix sont basés sur @stations. Le nom de la classe est select.
La clé définie dans le contrôleur est ** "choix affichés dans le menu déroulant" **, et la valeur est ** "valeur envoyée par les paramètres" **. Lorsque les gens choisissent, ils veulent choisir par nom de station, et lors de l'enregistrement des données, ils veulent s'associer par identifiant. C'est pourquoi j'ai défini la clé et la valeur de cette manière.
La figure qui les met en œuvre est la suivante.
Deux des mêmes tiroirs sont alignés et un est ouvert. Il est certain que station.name est affiché en option.
Dans l'image précédente, puisque la liste est faite à partir de données de table, ** il n'y a pas de "choix" de "ne pas sélectionner une station". ** ** Afin de rendre le commun "Veuillez choisir parmi ce qui suit", j'ai réécrit le contrôleur comme suit.
shops_controller.rb
def set_select_lists
@stations = Station.all.map {|station| [station.name, station.id] }.unshift(["Veuillez choisir parmi les suivants", nil])
end
J'ai ajouté .unshift (["Veuillez choisir ci-dessous", nil]) à @stations plus tôt. unshift est une méthode qui ajoute un élément au tout début d'un tableau. Nous avons ajouté l'option de passer nil à la valeur avec la phrase "Veuillez choisir parmi les éléments suivants" comme clé.
L'ajout d'un enregistrement tel que "Il n'y a pas de station la plus proche" aux données de la table elle-même n'est pas préférable car le nombre d'enregistrements dans la table intermédiaire augmentera inutilement, j'ai donc ajouté l'option permettant de définir la valeur sur zéro par moi-même.
Vous avez maintenant implémenté avec succès le menu déroulant souhaité.
Je pensais pouvoir m'enregistrer à ce stade, mais lorsque j'ai en fait ignoré les données des paramètres, le problème suivant s'est produit. ** Puisque les deux menus déroulants envoient des données avec la clé du même nom que station_ids, le résultat est que la deuxième valeur écrase la première valeur et qu'une seule valeur est envoyée. ** **
C'était évident quand j'ai regardé binding.pry. Cependant, ce que je veux faire ici est d'envoyer et d'enregistrer plusieurs station_ids. Autrement dit, je veux envoyer ** station_ids sous forme de tableau **
Je pense qu'il y a plusieurs façons de le faire, mais j'ai réécrit la vue comme suit (c'est probablement une technique de puissance, mais j'ai pu l'utiliser sous la forme après cela)
haml:new.html.haml
= f.select :station_ids, @stations,{},{name: 'shop[station_ids][]', class: "select"}
= f.select :station_ids, @stations,{},{name: 'shop[station_ids][]', class: "select"}
L'attribut de nom est ajouté à l'état précédent. Si vous ajoutez l'attribut name dans form_with, vous pouvez spécifier ** "Comment envoyer les paramètres?" **.
Si vous regardez réellement les paramètres dans binding.pry, vous pouvez voir comment les données sont envoyées. station_ids sont envoyés sous la forme ** params [: shop] [: station_ids] **.
Je voulais en faire un tableau, donc en ajoutant [] à la fin de l'attribut name, je peux envoyer les deux données en toute sécurité sous la forme d'un tableau.
shops_controller.rb
def shop_params
params.require(:shop).permit(:name, :address, :capacity, :owner_id, :genre_id, :mark_ids,introduces_attributes: [:content, :image, :number],station_ids: [])
end
En passant, j'ai mentionné plus tôt que les données ont été envoyées sous la forme de paramètres [: shop] [: station_ids], comme mentionné ci-dessus, avec le paramètre strong ** Tout d'abord, require: shop et appuyez sur la touche. Si vous le permettez, les données seront saisies en toute sécurité. ** ** J'ai bien compris cela dans binding.pry. Était drôle.
La méthode à spécifier avec l'attribut name est assez puissante, alors dites-moi si vous rencontrez une méthode plus intelligente. Cependant, chaque valeur du formulaire après cela a également été implémentée avec cela.
J'ai appris le plus en voyant comment les paramètres sont envoyés dans binding.pry.
Recommended Posts