8

如何为has_many :through具有附加属性的关联生成表单字段?

has_many :through关系有一个名为 的附加列weight

这是连接表的迁移文件:

create_table :users_widgets do |t|
  t.integer :user_id
  t.integer :widget_id
  t.integer :weight

  t.timestamps
end

模型如下所示:

User
  has_many :widgets, :through => :users_widgets,
           :class_name => 'Widget',
           :source => :widget
  has_many :users_widgets
  accepts_nested_attributes_for :widgets # not sure if this is necessary


Widget
  has_many :users, :through => :users_widgets,
           :class_name => 'User',
           :source => :user
  has_many :users_widgets
  accepts_nested_attributes_for :users # not sure if this is necessary


UsersWidget
  belongs_to :user
  belongs_to :widget

为简单起见,Widget 和 User 只有一个字段,称为nameergoUser.first.nameWidget.first.name

问题:

  • 如何将具有相应权重的小部件的下拉选择附加到用户创建/编辑表单?

  • 如何动态地将附加的小部件表单添加到用户或用户表单到小部件以轻松添加或删除这些关系?gem 似乎是完美的nested_form_for解决方案,但我无法让它工作。

  • 除了模型和表单部分之外,我的控制器是否需要进行任何更改?


快速说明.. 我对在用户表单中创建新小部件或在小部件表单中创建新用户不感兴趣,我只希望能够从现有对象中进行选择。

我正在运行 Rails 3.1 和 simple_form 2.0.0dev 来生成我的表单。

4

3 回答 3

6

根据你的问题。我做了一个简单的应用程序。源码在这里:https ://github.com/yakjuly/nest_form_example 我把它部署到heroku,你可以打开页面: http: //glowing-lightning-1954.heroku.com/users/new

答案

  1. 您希望用户表单可以选择带有重量的小部件,需要做更多的工作。下拉选择不能满足您的要求。

  2. 我在“bootstrap-rails”插件中混合“nested_form”,您可以更轻松地添加nested_fields

  3. 在我的示例中,您需要添加一个动作调用 select,并使 WidgetsController#create 可以 responsed_with :js

该代码基于simple_form,您可以尝试一下。

于 2011-12-13T09:54:20.777 回答
6

我将使用cocoon解决您的问题,cocoon是我为处理动态嵌套表单而创建的 gem。我还有一个示例项目来展示不同类型关系的示例。

你的不是字面上包括的,但并不难从中获得。在您的模型中,您应该编写:

class User 
  has_many :users_widgets
  has_many :widgets, :through -> :user_widgets

  accepts_nested_attributes_for :user_widgets, :reject_if => :all_blank, :allow_destroy => true

  #...
end

然后你需要创建一个局部视图,它会列出你链接的UserWidgets. 将此部分放在一个名为的文件中users/_user_widget_fields.html.haml

.nested-fields
  = f.association :widget, :collection => Widget.all, :prompt => 'Choose an existing widget'
  = f.input :weight, :hint => 'The weight will determine the order of the widgets'
  = link_to_remove_association "remove tag", f

然后你users/edit.html.haml可以写:

= simple_form_for @user do |f|
  = f.input :name

  = f.simple_fields_for :user_widgets do |user_widget|
    = render 'user_widget_fields', :f => user_widget
  .links
    = link_to_add_association 'add widget', f, :user_widgets

希望这可以帮助。

于 2011-12-17T10:04:33.707 回答
0

非常感谢茧指针 nathanvda。我一直在为尝试在 rails 4.0.0-rc1 下实现它时遇到的一些问题摸不着头脑,我想我会分享我的发现,以防万一有人在尝试这个 udner rails4 时遇到同样的问题。

以上面的代码为例,我确实将 user_id 和 widget_id 添加到允许的参数中,因为它们保存在连接表 user_widgets 中。在 rails 3 中,您必须将它们添加到用户模型中的 attr_accesible 中,但在 rails 4 中,您必须将它们添加到用于嵌套的主模型的控制器中的允许参数中,所以这里将是 users_controller:

params.require(:user).permit(...user_fields...,  
  user_widgets_attributes: [:user_id, :widget_id])

只这样做你最终会遇到几个问题:

  1. 更新用户记录时,每个关联(小部件)都会成倍增加。更新和保存记录时,1 变为 2、4、8 等等。
  2. 删除关联不起作用,该字段已从表单中删除,但关联仍保留在数据库中。

要解决这些问题,您还需要将 :id 和 :_destroy 添加到允许的属性列表中:

params.require(:user).permit(...user_fields...,  
  user_widgets_attributes: [:user_id, :widget_id, :id, :_destroy])

之后它完美地工作。

于尔根

PS:现在您必须使用 Gemfile 中的 git 存储库才能在 rails 4 下使用 cocoon,直到发布兼容 rails 4 的 gem。感谢关于我的错误报告的电子邮件 nathanvda!

于 2013-06-06T07:55:03.570 回答