Cette question revient souvent. Donc je me la sauvegarde pour la
prochaine fois :).

En gros la question c'est : comment mapper un formulaire sur du
has_and_belongs_to_many ou has_many :through. Par exemple User
has_and_belongs_to_many :roles. Je veux pouvoir afficher l'édition du
user avec la liste de tous les roles et des cases à cocher.

Y a une manière automatique de le faire qui ne nécessite aucune
modification ou traitement dans le controleur.

Une relation habtm ou hmt rajoute une méthode supplémentaire dans
l'instance du modèle dont le nom est le nom de la relation au
singulier suivi de _ids, donc dans l'exemple : role_ids. Cette méthode
renvoie la liste des ids des roles rattachés au user en question. Et
il y a aussi un setter !

Cela veut dire qu'on peut directement setter les roles en envoyant à
cette méthode un un tableau contenant les ids des roles. Donc comment
faire au niveau de la vue et du form... Comme cela :

<% Role.all.each do |role| %>
  <%= check_box_tag 'user[role_ids][]', role.id, @user.roles.include?(role) %>
  <%= role.name %>

<%= hidden_field_tag 'user[role_ids][]', '' %>

Et c'est tout. Dans le controleur on garde le traitement habituel CRUD
(du style User.new(params[:user]) ou
@user.update_attributes(params[:user])...

Pourquoi ce hidden_field_tag avec une chaine vide a la fin ? c'est
juste une bidouille pour que si aucune case n'est cochée, que Rails
reçoit un tableau vide, et donc vide correctement la liste d'ids.
Sinon, l'attribut role_ids n'existera pas dans les paramètres et rien
ne changera au niveau de la liste.

Nicolas.

2010/12/14 Michel Belleville <[email protected]>:
> Si tu regarde la doc sur check_box_tag :
> http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html
>
> Tu constate que sa signature est :
> check_box_tag(name, value = "1", checked = false, options = {})
>
> Donc le 3° arguments checked attend un booléen, par défaut false. Or en
> Ruby, quand on essaye d'utiliser n'importe quelle valeur à part false ou nil
> en tant que booléen, ça vaut true. Toi tu fais :
> user.profils.map {|p| p == profil}
>
> map renvoie un Array de valeurs renvoyées par le bloc de code que tu lui
> donne en itérant sur les valeurs de l'énumération, donc ici au lieu d'un
> booléen tu envoie un tableau, qui vaut true une fois converti en booléen.
>
> Peut-être que tu devrais utiliser la méthode any? au lieu de map ; any?
> itère sur chaque élément de l'énumération (comme map) jusqu'à trouver un
> élément pour lequel la valeur de retour de l'itérateur n'est pas false ou
> nil ; si elle en trouve un elle renvoie true, sinon elle itère sur tous les
> éléments et renvoie false après le dernier.
>
> En espérant que ça te débloque...
>
> Michel Belleville
>
>
> 2010/12/14 arnaud <[email protected]>
>>
>> Bonjour,
>>
>> j'ai besoin d'une petite appli web très simple donc j'en profite pour
>> tester rails3.
>>
>> En gros, j'ai une liste d'utilisateur et de profil.
>> Un utilisateur peut avoir 0 ou plusieurs profils et vice-versa.
>>
>> Je souhaite créer un tableau avec en ligne mes utilisateurs et en
>> colonne mes profils.
>> Pas de problème jusqu'ici.
>>
>> Là où ça pêche, c'est que je veux une case à cocher pour chaque droits
>> et que la case soit cochée ou pas si l'utilisateur a le profil ou pas.
>> Toutes mes checkbox sont cochées !
>>
>> Voyez-vous d'où vient mon erreur ?
>>
>> D'avance merci!
>>
>> Voila mon code :
>>
>> <table>
>>  <tr>
>>    <th>Firstname</th>
>>    <th>Lastname</th>
>>    <th>Login</th>
>> <% @profils.each do |profil| %>
>>    <th><%= profil.name %></th>
>> <% end %>
>>    <th></th>
>>    <th></th>
>>    <th></th>
>>  </tr>
>>
>> <% @users.each do |user| %>
>>  <tr>
>>    <td><%= user.firstname %></td>
>>    <td><%= user.lastname %></td>
>>    <td><%= user.login %></td>
>> <% @profils.each do |profil| %>
>>    <td><%= check_box_tag("profil_#{user.id}_#{profil.id}" , "yes",
>> user.profils.map{|p| p == profil}) %></td>
>> <% end %>
>>    <td><%= link_to 'Show', user %></td>
>>    <td><%= link_to 'Edit', edit_user_path(user) %></td>
>>    <td><%= link_to 'Destroy', user, :confirm => 'Are you
>> sure?', :method => :delete %></td>
>>  </tr>
>> <% end %>
>> </table>
>>
>> --
>> Vous avez reçu ce message, car vous êtes abonné au groupe "Railsfrance" de
>> Google Groups.
>> Pour transmettre des messages à ce groupe, envoyez un e-mail à l'adresse
>> [email protected]
>> Pour résilier votre abonnement envoyez un e-mail à l'adresse
>> [email protected]
>
> --
> Vous avez reçu ce message, car vous êtes abonné au groupe "Railsfrance" de
> Google Groups.
> Pour transmettre des messages à ce groupe, envoyez un e-mail à l'adresse
> [email protected]
> Pour résilier votre abonnement envoyez un e-mail à l'adresse
> [email protected]



-- 
Nicolas Blanco, Web developper

http://www.nicolasblanco.fr
Jabber/GoogleTalk : [email protected]
Twitter : http://twitter.com/slainer68
Github : http://github.com/slainer68
Skype : slainer68

-- 
Vous avez reçu ce message, car vous êtes abonné au groupe "Railsfrance" de 
Google Groups.
Pour transmettre des messages à ce groupe, envoyez un e-mail à l'adresse 
[email protected]
Pour résilier votre abonnement envoyez un e-mail à l'adresse 
[email protected]

Répondre à