5

我有一个非常简单的模型

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 自动整理到一个带有预填充可用职业的选项的保管箱中的。

我尝试使用has_many表单构建器方法,但这只能让我显示一个表单以输入 Lifestyle 的名称,并且在提交时,它返回了一个错误。

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

我得到的错误:

Can't mass-assign protected attributes: lifestyles_attributes

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

我非常怀疑这是否可以使用 ActiveAdmin 而不必创建非常复杂的逻辑来处理这个问题。如果您能给出您的意见并建议我是否应该这样做或以不同的方式处理它,我将非常感激。

4

3 回答 3

18

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

首先,我要感谢@Lichtamberg 提出的修复建议。但是,这只会使事情复杂化(也涉及安全性,尽管在这种情况下不是问题),并且无助于我达到理想的解决方案。

深入挖掘,我发现这是 Rails 中非常常见的场景,实际上在Ryan Bates 的截屏视频 #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. 或从表中删除时间戳

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

我希望这可以帮助其他有同样问题的人。

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

于 2012-11-01T20:09:41.520 回答
2

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

我说“可能”是因为我自己没有针对您的特定情况尝试过这个助手,但是这些东西倾向于自动工作,所以试试看。

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

于 2012-11-01T20:01:59.500 回答
0

添加

attr_accessible :lifestyles_attributes

费:

class AccountsController < ApplicationController
  attr_accessible :first_name, :last_name
end
于 2012-10-29T23:10:06.047 回答