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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 02:36:36  来源:igfitidea点击:

Rails 3: Multiple Select with has_many through associations

ruby-on-railsruby-on-rails-3

提问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)