has_and_belongs_to_many关系的自定义活动管理表单输入

我有一个非常简单的模型

class Lifestyle < ActiveRecord::Base attr_accessible :name has_and_belongs_to_many :profiles end 

Profilehas_and_belongs_to_many关系

 class Profile < ActiveRecord::Base attr_accessible ... belongs_to :occupation has_and_belongs_to_many :lifestyles accepts_nested_attributes_for :lifestyles end 

我想使用ActiveAdmin编辑Profile对象,但也将Lifestyles分配给配置文件。 它应该类似于处理belongs_to :occupation Occup,因为它由ActiveAdmin自动整理到一个预先填充了可用职业的选项的dropbox。

我曾尝试使用has_many表单构建器方法,但这只是让我显示一个表单来输入生活方式的名称,并在提交时,它返回了一个错误。

  f.object.lifestyles.build f.has_many :lifestyles do |l| l.input :name end 

我得到的错误:

 Can't mass-assign protected attributes: lifestyles_attributes 

对我来说,最好的方法是构建几个复选框 ,一个用于DB中的每个Lifestyle。 选择表示生活方式连接到配置文件,未选择意味着删除关系。

我非常怀疑使用ActiveAdmin可以实现这一点,并且无需创建非常复杂的逻辑来处理这个问题。 如果你提出你的意见并告诉我是否应该采用这种方式或采用不同的方法,我将非常感激。

经过一番研究,我准备回答我自己的问题。

首先,我要感谢@Lichtamberg建议修复。 然而,这只会使事情变得复杂(同样关于安全性,但在这种情况下不是问题),并且无法帮助我达到理想的解决方案。

挖掘更多,我发现这是Rails中非常常见的场景,实际上是在Ryan Bates的第17号电视剧中解释的。

因此,在Rails中,如果您有has_and_belongs_to_many(简短formsHABTM)关联,则可以通过此方法轻松设置其他关联对象的ID:

 profile.lifestyle_ids = [1,2] 

如果你为lifestyle_ids设置attr_accessible,这显然适用于表单:

 class Profile < ActiveRecord::Base attr_accessible :lifestyle_ids end 

在ActiveAdmin中,因为它使用Formtastic ,您可以使用此方法输出正确的字段(在本例中为复选框):

 f.input :lifestyles, as: :check_boxes, collection: Lifestyle.all 

另外,我简化了表单视图,所以它现在只是这样:

  form do |f| f.inputs # Include the default inputs f.inputs "Lifestlyes" do # Make a panel that holds inputs for lifestyles f.input :lifestyles, as: :check_boxes, collection: Lifestyle.all # Use formtastic to output my collection of checkboxes end f.actions # Include the default actions end 

好的,现在这在视图中完美呈现,但如果我尝试提交我的更改,它会给我这个数据库错误:

 PG::Error: ERROR: null value in column "created_at" violates not-null constraint : INSERT INTO "lifestyles_profiles" ("profile_id", "lifestyle_id") VALUES (2, 1) RETURNING "id" 

我发现这是因为Rails 3.2不会自动更新HABTM关联表的时间戳(因为它们是额外的属性,而Rails只处理_id属性)。

有两种解决方案可以解决这个问题:

  1. 将关联转换为hm:t( has_many, :through =>
  2. 或者从表中删除时间戳

我要去2)因为我永远不需要时间戳或任何额外的属性。

我希望这有助于其他人遇到同样的问题。

编辑: @cdesrosiers最接近解决方案,但在我读完之前我已经写了这个答案。 无论如何,这仍然很棒。 我学到了很多东西。

Active Admin在formtastic上创建了一个瘦DSL(特定于域的语言),所以当你需要表单定制时,最好查看一下formstic doc 。 在那里,你会发现你可以使用f.input :lifestyles, :as => :check_boxes来修改has_and_belongs_to_many关系。

我说“可能”,因为我没有亲自为你的特殊情况尝试过这个帮手,但是这些东西都有自动化的倾向,所以试试吧。

此外,您可能不需要accepts_nested_attributes_for :lifestyles除非您真的想要修改profileslifestyles属性,我认为这在使用活动管理员时不会特别有用(只需直接修改lifestyles )。

 attr_accessible :lifestyles_attributes 

FE:

 class AccountsController < ApplicationController attr_accessible :first_name, :last_name end