Ruby-on-rails Rails 3:通过关联使用 has_many 进行多项选择
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8826407/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rails 3: Multiple Select with has_many through associations
提问by Oleg Pasko
I want to get possibility to select several Categories for one Post with multiple select.
我希望可以通过多项选择为一个帖子选择多个类别。
I have next models: Post, Category and PostCategory.
我有下一个模型: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
In my controller I have something like @post = Post.new . I've created some categories.
在我的控制器中,我有类似 @post = Post.new 的东西。我创建了一些类别。
And in view I have:
鉴于我有:
<%= form_for @post do |f| %>
<%= f.text_field :title %>
<%= f.select :categories, :multiple => true %>
<%= f.submit %>
<% end %>
And... where is my categories? I have only "multiple" in select options. I think it's something wrong with my form.
而且...我的类别在哪里?我在选择选项中只有“多个”。我觉得我的表格有问题。
回答by winfred
Sorry to resurrect the dead, but I found a much simpler solution that lets one use the default controller action code and use the ActiveModel setter logic for a has_many. Yes, it's totally magic.
很抱歉让死者复活,但我找到了一个更简单的解决方案,它可以让一个人使用默认的控制器操作代码,并为 has_many 使用 ActiveModel setter 逻辑。是的,这完全是魔术。
<%= f.select :category_ids, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>
Specifically, using the :category_ids (or :your_collection_ids) param name will automagically tell Rails to call
@post.category_ids = params[:post][:category_ids]to set the categories for that post accordingly, all without modifying the default controller/scaffold #create and #update code.
具体来说,使用 :category_ids(或 :your_collection_ids)参数名称将自动告诉 Rails 调用
@post.category_ids = params[:post][:category_ids]以相应地设置该帖子的类别,而无需修改默认的控制器/脚手架 #create 和 #update 代码。
Oh, and it works with has_many :something, through: :something_elseautomatically managing the join model. Freaking awesome.
哦,它可以has_many :something, through: :something_else自动管理连接模型。真棒。
So from the OP, just change the field/param name to :category_idsinstead of :categories.
因此,在 OP 中,只需将字段/参数名称更改:category_ids为:categories.
This will also automatically have the model's selected categories populate the select field as highlighted when on an edit form.
这也将自动让模型的选定类别填充在编辑表单上突出显示的选择字段。
References:
参考:
From the has_many API docswhere I found this.
从我发现的 has_many API 文档中。
Also the warning from the form helpers guideexplains this "type mismatch" when not using the proper form-field/parameter name.
当不使用正确的表单字段/参数名称时,表单助手指南中的警告也解释了这种“类型不匹配”。
By using the proper form-field/param name, you can dry up new and edit forms and keep the controllers thin, as encouraged by the Rails way.
通过使用正确的表单字段/参数名称,您可以像 Rails 方式所鼓励的那样,干掉新的和编辑的表单并保持控制器的精简。
note for rails 4 and strong parameters:
Rails 4 和强参数的注意事项:
def post_params
params.require(:post).permit(:title, :body, category_ids: [])
end
回答by Oleg Pasko
Final solution to organize categories in your posts, I hope it will be useful.
在您的帖子中组织类别的最终解决方案,我希望它会有所帮助。
To use multiple we need select_tag:
要使用多个我们需要 select_tag:
<%= select_tag "categories", options_from_collection_for_select(Categories.all, 'id', 'name'), :multiple => true %>
Or f.select (many thanks to Tigraine and Brent!), it's more elegant way:
或者 f.select (非常感谢 Tigraine 和 Brent!),这是更优雅的方式:
<%= f.select :categories, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>
In create action of our controller we need:
在我们的控制器的创建动作中,我们需要:
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
回答by Brent Sowers
Tigraine almost had it, but you need to specify an additional empty hash:
Tigraine 几乎拥有它,但您需要指定一个额外的空哈希:
<%= f.select :category_id, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>
<%= f.select :category_id, Category.all.collect {|x| [x.name, x.id]}, {}, :multiple => true %>
回答by Tigraine
What you need is a list of options for the select:
您需要的是选择的选项列表:
<%= f.select :category_id, Category.all.collect {|x| [x.name, x.id]}, :multiple => true %>
回答by naren
As the @post does not have id, the from might not display categories as there is no association. You need to pass do a build on @post something like
由于@post 没有 id,from 可能不会显示类别,因为没有关联。您需要通过在@post 上进行构建,例如
@post = Post.new(:categories => Category.all)

