通过与其他属性相关联来创建has_many的Rails表单?

时间:2020-12-31 05:27:47

How can I generate form fields for a has_many :through association that has additional attributes?

如何为has_many生成表单字段:通过具有其他属性的关联?

The has_many :through relationship has an additional column called weight.

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

Here's the migration file for the join table:

这是连接表的迁移文件:

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

  t.timestamps
end

The models look like this:

模型看起来像这样:

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

For the sake of simplicity, Widget and User only have one field of their own called name, ergo User.first.name and Widget.first.name

为简单起见,Widget和User只有一个名为ergo User.first.name和Widget.first.name的字段。

Questions:

  • How would I append a dropdown selection for Widgets with the corresponding weight to the User create/edit form?

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

  • How can I dynamically add additional Widget forms to Users or User forms to Widgets to easily add or remove these relationships? The nested_form_for gem seems to be the perfect solution but I haven't been able to get it working.

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

  • Apart from the models and the form partials, are there any changes that need to be made to my controller?

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


Quick note.. I'm not interested in creating new Widgets in the User form or new Users in the Widget form, I only want the ability to select from existing objects.

快速注释..我对在用户窗体中创建新窗口小部件或在窗口小部件窗体中创建新用户不感兴趣,我只希望能够从现有对象中进行选择。

I'm running Rails 3.1 and simple_form 2.0.0dev for generating my forms.

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

3 个解决方案

#1


6  

I will be solving your problem using cocoon, a gem I created to handle dynamically nested forms. I also have an example project to show examples of different types of relationships.

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

Yours is not literally included, but is not that hard to derive from it. In your model you should write:

你的字面意思并不完全包含在内,但并不难从中衍生出来。在你的模型中你应该写:

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

Then you need to create a partial view which will list your linked UserWidgets. Place this partial in a file called users/_user_widget_fields.html.haml:

然后,您需要创建一个部分视图,列出您链接的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

In your users/edit.html.haml you can then write:

在您的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

Hope this helps.

希望这可以帮助。

#2


6  

base your question. I made a simple App. source is here: https://github.com/yakjuly/nest_form_example I deployed it to heroku, you can open page: http://glowing-lightning-1954.heroku.com/users/new

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

answers

  1. you want user form can select widget with weight, need do more work.dropdown selection can not satisfy your requirement.

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

  2. I mix "nested_form" in a "bootstrap-rails" plugin, you can add the nested_fields easier

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

  3. in my example, you need add a action calls select, and make WidgetsController#create can responsed_with :js

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

the code is based simple_form, you can have a try.

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

#3


0  

Thanks a lot for the cocoon pointer nathanvda. I have been scratching my head about some problems I had when trying to implement this under rails 4.0.0-rc1 and I thought I would share my findings just in case someone has the same problems when attempting this udner rails4.

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

Using the above code as an example, I did add user_id and widget_id to the permitted parameters as they are saved in the connecting table user_widgets. In rails 3 you did have to add them to attr_accesible in the user model but in rails 4 you have to add them to the allowed parameters in the controller of the main model you use for nesting, so here that would be the users_controller:

使用上面的代码作为示例,我确实将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])

Doing only this you end up with several of problems:

只做这件事你最终遇到了几个问题:

  1. Every association (widget) gets multiplied when updating a user record. 1 becomes 2, 4, 8, and so on, when updating and saving the record.
  2. 更新用户记录时,每个关联(窗口小部件)都会成倍增加。更新和保存记录时,1变为2,4,8等。

  3. removing an association does not work, the field is removed from the form but the association remains in the DB.
  4. 删除关联不起作用,该字段将从表单中删除,但关联仍保留在数据库中。

To fix these problems you also need to add :id and :_destroy to the list of permitted attributes:

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

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

after that it works flawlessly.

之后,它完美无缺。

Juergen

PS: For now you have to use the git repository in your Gemfile to use cocoon under rails 4 until a rails 4 compatible gem is released. Thanks for the email nathanvda on my bug report!!

PS:现在你必须使用你的Gemfile中的git存储库在rails 4下使用cocoon,直到释放了rails 4兼容的gem。感谢我的错误报告中的nathanvda电子邮件!!

#1


6  

I will be solving your problem using cocoon, a gem I created to handle dynamically nested forms. I also have an example project to show examples of different types of relationships.

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

Yours is not literally included, but is not that hard to derive from it. In your model you should write:

你的字面意思并不完全包含在内,但并不难从中衍生出来。在你的模型中你应该写:

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

Then you need to create a partial view which will list your linked UserWidgets. Place this partial in a file called users/_user_widget_fields.html.haml:

然后,您需要创建一个部分视图,列出您链接的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

In your users/edit.html.haml you can then write:

在您的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

Hope this helps.

希望这可以帮助。

#2


6  

base your question. I made a simple App. source is here: https://github.com/yakjuly/nest_form_example I deployed it to heroku, you can open page: http://glowing-lightning-1954.heroku.com/users/new

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

answers

  1. you want user form can select widget with weight, need do more work.dropdown selection can not satisfy your requirement.

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

  2. I mix "nested_form" in a "bootstrap-rails" plugin, you can add the nested_fields easier

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

  3. in my example, you need add a action calls select, and make WidgetsController#create can responsed_with :js

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

the code is based simple_form, you can have a try.

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

#3


0  

Thanks a lot for the cocoon pointer nathanvda. I have been scratching my head about some problems I had when trying to implement this under rails 4.0.0-rc1 and I thought I would share my findings just in case someone has the same problems when attempting this udner rails4.

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

Using the above code as an example, I did add user_id and widget_id to the permitted parameters as they are saved in the connecting table user_widgets. In rails 3 you did have to add them to attr_accesible in the user model but in rails 4 you have to add them to the allowed parameters in the controller of the main model you use for nesting, so here that would be the users_controller:

使用上面的代码作为示例,我确实将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])

Doing only this you end up with several of problems:

只做这件事你最终遇到了几个问题:

  1. Every association (widget) gets multiplied when updating a user record. 1 becomes 2, 4, 8, and so on, when updating and saving the record.
  2. 更新用户记录时,每个关联(窗口小部件)都会成倍增加。更新和保存记录时,1变为2,4,8等。

  3. removing an association does not work, the field is removed from the form but the association remains in the DB.
  4. 删除关联不起作用,该字段将从表单中删除,但关联仍保留在数据库中。

To fix these problems you also need to add :id and :_destroy to the list of permitted attributes:

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

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

after that it works flawlessly.

之后,它完美无缺。

Juergen

PS: For now you have to use the git repository in your Gemfile to use cocoon under rails 4 until a rails 4 compatible gem is released. Thanks for the email nathanvda on my bug report!!

PS:现在你必须使用你的Gemfile中的git存储库在rails 4下使用cocoon,直到释放了rails 4兼容的gem。感谢我的错误报告中的nathanvda电子邮件!!