Je veux avoir la possibilité de sélectionner plusieurs catégories pour une publication avec plusieurs sélections.
J'ai les modèles suivants: Post, Category et PostCategory.
class Post < ActiveRecord::Base
has_many :post_categories
has_many :categories, :through => :post_categories
end
class Category < ActiveRecord::Base
has_many :post_categories
has_many :posts, :through => :post_categories
end
class PostCategory < ActiveRecord::Base
has_one :post
has_one :category
belongs_to :post # foreign key - post_id
belongs_to :category # foreign key - category_id
end
Dans mon contrôleur, j'ai quelque chose comme @post = Post.new . J'ai créé des catégories.
Et en vue j'ai:
<%= form_for @post do |f| %>
<%= f.text_field :title %>
<%= f.select :categories, :multiple => true %>
<%= f.submit %>
<% end %>
Et ... où sont mes catégories? Je n'ai que "plusieurs" dans les options de sélection. Je pense que quelque chose ne va pas avec ma forme.
Désolé de ressusciter les morts, mais j'ai trouvé une solution beaucoup plus simple qui permet d'utiliser le code d'action par défaut du contrôleur et d'utiliser la logique de définition ActiveModel pour un has_many. Oui, c'est totalement magique.
<%= f.select :category_ids, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>
Plus précisément, l'utilisation du nom de paramètre: category_ids (ou: your_collection_ids) indiquera automatiquement à Rails d'appeler @ post.category_ids = params [: post] [: category_ids] pour définir les catégories de ce message en conséquence, sans modifier le contrôleur/échafaudage par défaut. #create et #update code.
Oh, et cela fonctionne avec has_many: quelque chose, via:: quelque chose, de gérer automatiquement le modèle de jointure. Super génial.
Donc, à partir de l'OP, changez simplement le nom du champ/param en: category_ids au lieu de: categories.
Ainsi, les catégories sélectionnées du modèle seront automatiquement renseignées dans le champ de sélection tel qu'il est mis en surbrillance dans un formulaire de modification.
Références:
À partir de la documentation de l'API has_many où j'ai trouvé ceci.
Également l'avertissement du guide des aides de formulaire explique cette "incompatibilité de type" lorsque vous n'utilisez pas le nom de champ/paramètre correct.
En utilisant le nom de formulaire/paramètre approprié, vous pouvez sécher les nouveaux formulaires et les modifier, tout en maintenant les contrôleurs minces, comme le préconise la méthode Rails.
note pour Rails 4 et les paramètres forts:}
def post_params
params.require(:post).permit(:title, :body, category_ids: [])
end
Solution finale pour organiser les catégories dans vos messages, j'espère que cela vous sera utile.
Pour utiliser plusieurs, nous avons besoin de select_tag:
<%= select_tag "categories", options_from_collection_for_select(Categories.all, 'id', 'name'), :multiple => true %>
Ou f.select ( merci beaucoup à Tigraine et Brent! ), c’est plus élégant:
<%= f.select :categories, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>
Pour créer une action de notre contrôleur, nous avons besoin de:
def create
@post = Post.new(params[:post])
if @post.save
params[:categories].each do |categories|
categories = PostCategory.new(:category_id => categories, :post_id => @post.id)
if categories.valid?
categories.save
else
@errors += categories.errors
end
end
redirect_to root_url, :notice => "Bingo!"
else
render "new"
end
end
Ce dont vous avez besoin est une liste d’options pour la sélection:
<%= f.select :category_id, Category.all.collect {|x| [x.name, x.id]}, :multiple => true %>
Tigraine l'avait presque, mais vous devez spécifier un hachage vide supplémentaire:
<%= f.select :category_id, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>
Comme @post n'a pas d'identifiant, il est possible que le de n'affiche pas de catégories car il n'y a pas d'association. Vous devez réussir à construire @post quelque chose comme
@post = Post.new(:categories => Category.all)