Rails 3:通过关联使用has_many进行多选

我想要获得select多个select的一个职位的几个类别的可能性。

我有下一个模型:Post,Category和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 

在我的控制器中,我有类似@post = Post.new的东西。 我创build了一些类别。

而在我看来,我有:

 <%= form_for @post do |f| %> <%= f.text_field :title %> <%= f.select :categories, :multiple => true %> <%= f.submit %> <% end %> 

而…我的分类在哪里? 我在select选项中只有“多个”。 我认为这是我的表单有问题。

对不起复活死人,但我发现一个更简单的解决scheme,让一个使用默认的控制器操作代码,并使用ActiveModel设置逻辑has_many。 是的,这完全是魔法。

 <%= f.select :category_ids, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %> 

具体来说,使用:category_ids(或:your_collection_ids)参数名称将自动告诉Rails调用@ post.category_ids = params [:post] [:category_ids]来相应地设置该post的类别,而不用修改默认控制器/脚手架#create和#update代码。

哦,它和has_many一起工作:通过:: something_else,自动pipe理连接模型。 吓坏了真棒。

所以从OP中,只要将字段/参数名称更改为:category_ids而不是:categories。

这也会自动让模型的所选类别在编辑表单中突出显示。

参考文献:

从has_many API文档 ,我发现这一点。

另外,表单助手指南中的警告解释了这种“types不匹配”,当不使用适当的表单域/参数名称。

通过使用适当的form-field / param名称,您可以烘干新的和编辑表单,并保持控制器的精简,正如Rails方式所鼓励的。

注意导轨4和强参数:

 def post_params params.require(:post).permit(:title, :body, category_ids: []) end 

最后的解决scheme,在您的post中组织类别,我希望这将是有益的。

要使用多个,我们需要select_tag:

 <%= select_tag "categories", options_from_collection_for_select(Categories.all, 'id', 'name'), :multiple => true %> 

或f.select( 非常感谢Tigraine和Brent! ),这是更优雅的方式:

 <%= f.select :categories, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %> 

在我们的控制器创build行动中,我们需要:

 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 

你需要的是select的选项列表:

 <%= f.select :category_id, Category.all.collect {|x| [x.name, x.id]}, :multiple => true %> 

Tigraine几乎有它,但你需要指定一个额外的空哈希:

<%= f.select :category_id, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>

由于@post没有ID,因此可能不会显示类别,因为没有关联。 你需要传递一个@post的东西

  @post = Post.new(:categories => Category.all)