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

时间:2012-10-29 22:52:05

标签: ruby-on-rails ruby-on-rails-3 forms associations activeadmin

我有一个非常简单的模型

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

Profile关系的

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,因为它由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

对我而言,完美的方法是建立几个复选框,一个用于数据库中的每个生活方式。选择表示生活方式与配置文件相关联,未选择表示删除关系。

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

3 个答案:

答案 0 :(得分:18)

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

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

进一步挖掘,我发现这是Rails中非常常见的情况,实际上是在Ryan Bates' screencast no #17中解释的。

因此,在Rails中,如果您有has_and_belongs_to_many(简写HABTM)关联,则可以通过此方法轻松设置其他关联对象的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. 或从表中删除时间戳
  3. 我要去2)因为我永远不需要时间戳或任何额外的属性。

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

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

答案 1 :(得分:2)

Active Admin会在formtastic上创建一个瘦DSL(特定于域的语言),因此在需要表单自定义时最好查看formastic doc。在那里,您会发现您可以使用f.input :lifestyles, :as => :check_boxes修改has_and_belongs_to_many关系。

我说“可能”因为我没有亲自为你的特定情况尝试这个帮助,但是这些东西倾向于自动运行,所以试一试。

此外,您可能不需要accepts_nested_attributes_for :lifestyles,除非您确实要从lifestyles修改profiles的属性,我认为这在使用活动管理员时并不特别有用(只需直接修改lifestyles

答案 2 :(得分:0)

添加

attr_accessible :lifestyles_attributes

f.e:

class AccountsController < ApplicationController
  attr_accessible :first_name, :last_name
end