Quelqu'un peut-il m'expliquer collection_select en termes clairs et simples?

146

Je suis en train de parcourir les documents de l'API Rails pour collection_selectet ils sont horribles.

Le titre est le suivant:

collection_select(object, method, collection, value_method, text_method, options = {}, html_options = {})

Et c'est le seul exemple de code qu'ils donnent:

collection_select(:post, :author_id, Author.all, :id, :name_with_initial, :prompt => true)

Quelqu'un peut-il expliquer, en utilisant une simple association (disons a Userhas_many Plans, et a Planappartient à a User), ce que je veux utiliser dans la syntaxe et pourquoi?

Edit 1: De plus, ce serait génial si vous expliquiez comment cela fonctionne dans un form_helperformulaire ou un formulaire régulier. Imaginez que vous expliquez cela à un développeur Web qui comprend le développement Web, mais qui est «relativement nouveau» pour Rails. Comment l'expliquerais-tu?

marcamillion
la source
50
Oui. C'est la documentation la plus horrible que j'aie jamais vue
Jaseem
1
Pour être honnête, la documentation est tout à fait correcte, mais pas dans le FormBuildermais dans le FormOptionsHelper: api.rubyonrails.org/classes/ActionView/Helpers/…
amiuhle
1
Ma partie préférée est lorsque vous utilisez collection_select dans un formulaire et que cela change la signature entière de sorte que l'objet ne fasse pas partie de la liste de paramètres, mais à la place collection_select est appelée en tant que méthode sur l'objet. Ne pensez pas qu'ils mentionnent cela dans la documentation ...
user3670743
1
C'est un projet open source: si la documentation est pauvre, nous n'avons que nous-mêmes à blâmer; cela pourrait être incroyable si seulement nous faisions notre part pour l'améliorer. Les PR petits / simples vont très loin.
BKSpurgeon

Réponses:

305
collection_select(
    :post, # field namespace 
    :author_id, # field name
    # result of these two params will be: <select name="post[author_id]">...

    # then you should specify some collection or array of rows.
    # It can be Author.where(..).order(..) or something like that. 
    # In your example it is:
    Author.all, 

    # then you should specify methods for generating options
    :id, # this is name of method that will be called for every row, result will be set as key
    :name_with_initial, # this is name of method that will be called for every row, result will be set as value

    # as a result, every option will be generated by the following rule: 
    # <option value=#{author.id}>#{author.name_with_initial}</option>
    # 'author' is an element in the collection or array

    :prompt => true # then you can specify some params. You can find them in the docs.
)

Ou votre exemple peut être représenté comme le code suivant:

<select name="post[author_id]">
    <% Author.all.each do |author| %>
        <option value="<%= author.id %>"><%= author.name_with_initial %></option>
    <% end %>
</select>

Ce n'est pas documenté dans le FormBuilder, mais dans leFormOptionsHelper

alexkv
la source
32
C'est facilement l'une des meilleures explications d'une structure Rails complexe que j'ai vue. Vous avez utilisé un langage clair, ainsi que des constructions de base de Rails pour le solidifier. Merci beaucoup!!
marcamillion
2
Pourquoi le nommeriez-vous "post [author_id]"?
Jaseem
@alexkv merci - seriez-vous en mesure de préciser la signification des paramètres: post, # field namespace et: author_id, # field name parameters (les deux premiers) - je ne comprends pas leur but dans le schéma des choses - peut ' t-ils être omis?
BKSpurgeon
1
Le premier paramètre peut en effet être nul. Si vous créez un formulaire objet, ce sera cet objet afin que la sélection ait le même espace de noms que le reste du formulaire. Si ce n'est pas nécessaire, laissez le 1er comme nul. Le 2ème est le nom du champ, donc s'il s'agit de mettre à jour un champ sur un objet (1er paramètre) alors le nom du champ est le deuxième paramètre. Si vous créez un formulaire pour d'autres utilisations, le deuxième paramètre est celui que vous voulez que le contrôle de formulaire soit nommé et identifié. Pourquoi l'utiliser avec nil 1st? Probablement parce que vous voulez collection_select pour les options: prompt.
elc
1
Je dois également noter que vous pouvez obtenir le même effet en plaçant un paramètre d'invite sur un select_tag qui utilise options_for_select, ce qui répondrait probablement de la même manière qu'un collection_select avec un objet nil.
elc
21

J'ai moi-même passé pas mal de temps sur les permutations des balises sélectionnées.

collection_selectcrée une balise de sélection à partir d'une collection d'objets. Gardant cela à l'esprit,

object: Nom de l'objet. Ceci est utilisé pour générer le nom de la balise et pour générer la valeur sélectionnée. Cela peut être un objet réel ou un symbole - dans ce dernier cas, la variable d'instance de ce nom est recherchée dans la liaison duActionController (c'est-à-dire qu'elle :postrecherche une instance var appelée @postdans votre contrôleur.)

method: Nom de la méthode. Ceci est utilisé pour générer le nom de la balise. En d'autres termes, l'attribut de l'objet que vous essayez d'obtenir de la sélection

collection : La collection d'objets

value_method : Pour chaque objet de la collection, cette méthode est utilisée pour la valeur

text_method : Pour chaque objet de la collection, cette méthode est utilisée pour afficher du texte

Paramètres facultatifs:

options: Options que vous pouvez passer. Ceux-ci sont documentés ici , sous la rubrique Options.

html_options: Tout ce qui est passé ici, est simplement ajouté à la balise html générée. Si vous souhaitez fournir une classe, un identifiant ou tout autre attribut, il va ici.

Votre association pourrait s'écrire:

collection_select(:user, :plan_ids, Plan.all, :id, :name, {:prompt => true, :multiple=>true })

En ce qui concerne l'utilisation form_for, encore une fois en termes très simples, pour toutes les balises qui entrent dans form_for, par exemple.f.text_field, vous n'avez pas besoin de fournir le premier objectparamètre ( ). Ceci est tiré de la form_forsyntaxe.

zsquare
la source
2
Merci d'avoir pris le temps ... le seul problème est que, en toute honnêteté, votre explication n'aide pas à clarifier les choses dans ma tête. Vous avez utilisé beaucoup de termes dans la définition réelle. J'apprécie cependant que vous preniez le temps - donc pour cela, j'ai voté.
marcamillion
4
Pour les raisons si clairement exposées par marcamillion, j'ai voté contre.
Jamie