【问题标题】:Using nested attributes to easily select associations in a form使用嵌套属性轻松选择表单中的关联
【发布时间】:2012-11-08 04:42:49
【问题描述】:

我正在尝试创建一个嵌套属性表单来创建一个模型,该模型主要是其他两个模型之间的关联“连接器”。在我的例子中,模型代表booksawards 和“连接器”模型book_awards。当我在编辑一本书时,我希望能够快速选择它获得了哪些奖项。

我一直在使用 http://railscasts.com/episodes/196-nested-model-form-part-1 帮助我开始,但恐怕我几乎被卡住了。

另一个看起来相似的 SO 问题是 accepts_nested_attributes_for with find_or_create? 不幸的是,这也不是我正在做的事情,我无法适应它。

我的模型看起来像这样。每个模型都有额外的属性和验证等,但为了清楚起见,我删除了它们。

class Book < ActiveRecord::Base
  has_many :book_awards
  accepts_nested_attributes_for :book_awards, :allow_destroy => true
end

class Award < ActiveRecord::Base
  has_many :book_awards
end

class BookAward < ActiveRecord::Base
  belongs_to :book, :award
end

在我的书中用于编辑和新建的控制器方法,以及用于创建和更新的失败案例中,我有一行 @awards = Award.all

在我看来,我希望看到所有奖项旁边带有复选框的列表。当我提交时,我想更新、创建或销毁book_award 模型。如果选中该复选框,我想更新现有模型或创建一个新模型(如果它不存在)。如果未选中该复选框,那么我想销毁现有模型,或者如果奖励从不存在,则什么也不做。我有book_awards 的部分内容。我不确定复选框选择器是否应该在这个部分中。

我认为我的复选框将成为:_destroy 的钩子,但它的极性颠倒了。我认为这样的事情基本上可以做到:

= f.check_box :_destroy, {}, 0, 1

目前,我的部分中有这个,但我不确定它到底属于哪里。

接下来是我目前不起作用的观点,但也许它有助于展示我正在尝试做的事情。我遍历awards 并使用fields_for 为已经存在的任何内容设置嵌套属性。它非常丑陋,但我认为它有点工作。但是,我真的不知道如何开始使用 else 案例。

= f.label :awards
- @awards.each do |a|
  - if f.object.awards && f.object.awards.include?(a)
    = f.fields_for :book_awards, f.object.book_award.select{|bas| bas.award == a } do |ba|
      = render 'book_awards', :f => ba, :a => a
  - else
    = fields_for :book_awards do |ba|
      = render 'book_awards', :f => ba, :a => a

我希望每次都以相同的顺序列出奖项(我在控制器中的@awards 分配可能会指定顺序),而不是首先或最后列出现有的奖项。

【问题讨论】:

    标签: ruby-on-rails-3 forms associations nested-attributes fields-for


    【解决方案1】:

    我不想回答自己的问题,但我终于找到了可行的方法。我需要做的第一件事是根据 railscast 中包含的疯狂对象更新“新”案例。接下来,我需要手动设置:child_index。最后,我需要手动适当地设置:_destroy复选框。

    .field
      = f.label :awards
      - @awards.each_with_index do |a,i|
        - if exists = (f.object.awards && f.object.awards.include?(a))
          - new_ba = f.object.book_awards.select{|s| s.award == a}
        - else
          - new_ba = f.object.class.reflect_on_association(:book_awards).klass.new
        = f.fields_for :book_awards, new_ba, :child_index => i do |ba|
          = render 'book_awards', :f => ba, :a => a, :existing => exists
    

    我的部分看起来像这样:

    .field
      = f.check_box :_destroy, {:checked => existing}, 0, 1
      = f.label a.name
      = f.hidden_field :award_id, :value => a.id
      = f.label :year
      = f.number_field :year
    

    它不是非常漂亮,但它似乎完全符合我的要求。

    【讨论】:

    • 如果有人关心,f.object.class.reflect_on_association(:book_awards).klass.new 在这种情况下可以简化为 BookAward.new
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-08
    • 2023-03-09
    • 2014-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-11
    相关资源
    最近更新 更多