嵌套表单和has_many:通过

时间:2012-06-18 16:34:59

标签: ruby-on-rails ruby-on-rails-3

我有一个小样本应用程序,其中有3个模型:成员,组和订阅。我们的想法是会员可以订阅群组。

ERD

class Member < ActiveRecord::Base
  has_many :subscriptions, dependent: :delete_all
  has_many :groups, through: :subscriptions

  attr_accessible :email

  validates :email, presence: true
end

class Group < ActiveRecord::Base
  has_many :subscriptions, dependent: :delete_all
  has_many :members, through: :subscriptions

  accepts_nested_attributes_for :subscriptions

  attr_accessible :name, :subscriptions_attributes

  validates :name, presence: true, uniqueness: true
end

class Subscription < ActiveRecord::Base
  belongs_to :group
  belongs_to :member

  attr_accessible :group_id, :introduction

  validates :group_id, presence: true
  validates :introduction, presence: true
end

我正在尝试为新组创建表单,并将introduction属性嵌套在其中。

我的控制器方法:

def new
  @group = Group.new
  @group.subscriptions.build
end

def create
  @member = Member.first
  @group = @member.groups.build(params[:group])

  if @group.save
    flash[:success] = "Saved"
    redirect_to group_path(@group)
  else
    render :new
  end
end

但它不起作用。它会抛出错误group_id can't be blank。所以我不知道如何将新组分配给订阅。

此外,member_id正在创建为nil。但正如您所看到的,我正在使用@member变量创建组,因此我认为它应该初始化,但事实并非如此。

任何人都可以向我展示光明吗?

您可以在此处查看示例应用:https://github.com/idavemm/nested_form

4 个答案:

答案 0 :(得分:0)

确保您尝试分配的所有属性都是attr_accessible。您可以禁用它并查看它是否有效,或者查看Rails服务器日志中的警告。

更新:您应该将accepts_nested_attributes_for添加到Member模型,并使用带有fields_for的多模型表单。

答案 1 :(得分:0)

我认为你是以错误的方式思考你的模型。每个成员是否会对每个小组有不同的介绍。那么,例如,member1有一个介绍,member2有不同的介绍吗?

订阅模型应存储有关成员和组之间关系的信息。在这种情况下,在组模型中引入会更好。 您收到错误的原因是您尝试为尚未制作的论坛创建订阅(当您设置简介属性时)。

因此,移动对组模型的介绍,然后,如果您希望组的创建者自动订阅它(您应该),请添加代码以在创建操作之后创建对控制器的订阅记录已保存。然后,在订阅模型上,你可以做一些很酷的事情,比如拥有一个状态机来跟踪成员的状态(主持人,新手,资深成员等)。

答案 2 :(得分:0)

经过数小时的调查和挫折,我向Rails开发者报告了这件事,我终于找到了解决方案:

Rails 3无法按照问题中定义的方式自动初始化group_id和member_id。

所以,现在,有两种方法可以让它发挥作用:

  1. 将member_id添加为视图中的隐藏字段。
  2. 更改所有内容,具有accepts_nested_attributes_for的订阅模型也是如此。这样,要创建的新对象是Subscription,Group将是嵌套模型。
  3. 第一个选项有一个重要的安全漏洞,所以我不推荐它。

    第二种选择虽然不太合乎逻辑,但它更清晰,可以说是解决这个问题的“Rails方式”。

答案 3 :(得分:0)

我刚遇到同样的问题,解决方法是从相关模型中删除状态验证(基于this question),在您的情况下,删除:

验证:group_id,presence:true

一旦验证结束,一切都像发条一样运行