【问题标题】:Rails forms for has_many through association with additional attributes?通过与附加属性关联的has_many 的Rails 表单?
【发布时间】:2012-01-11 06:49:51
【问题描述】:

如何为具有附加属性的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 只有一个字段,分别称为 name、ergo User.first.nameWidget.first.name

问题:

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

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

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


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

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

【问题讨论】:

    标签: ruby-on-rails ruby nested-forms has-many-through simple-form


    【解决方案1】:

    我将使用cocoon 解决您的问题,这是我创建的用于处理动态嵌套表单的 gem。我也有an example project 来展示不同类型关系的示例。

    你的不是字面意思,但并不难从中获得。在你的模型中你应该写:

    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
    

    希望这会有所帮助。

    【讨论】:

    • 谢谢@nathanvda,这正是我想要的。您的宝石使这变得特别容易。 PS:赏金是在我给你之前自动分配的,但我已经 ping 了模组寻求帮助。
    • 设置了几乎完全相同的模型,这非常有用。我发现像这种漂亮的思维弯曲的复杂形式,感谢您的精彩宝石/答案!
    • 我知道这不是很好的评论形式,但我只想说非常感谢。大约 6 个小时,我一直在试图弄清楚如何应用 Cocoon 来加入表格,并且几乎准备放弃。
    【解决方案2】:

    根据您的问题。我做了一个简单的应用程序。 来源在这里: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的,你可以试试。

    【讨论】:

      【解决方案3】:

      非常感谢茧指针 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!

      【讨论】:

        猜你喜欢
        • 2015-08-22
        • 2014-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-18
        • 2016-03-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多