"无法修改关联,因为源反射类通过以下方式关联:has_many"

时间:2015-09-15 11:21:27

标签: ruby-on-rails ruby-on-rails-4

我已经查看过具有类似标题和问题的其他问题,但他们的解决方案似乎并不适用于我。很抱歉没有更具描述性,我已达到150限制。

我有以下型号:

class Event < ActiveRecord::Base
  has_many :weeks, dependent: :destroy
  has_many :tests, through: :weeks

  accepts_nested_attribues_for :weeks, allow_destroy: true
  accepts_nested_attribues_for :tests, allow_destroy: true
end

class Week < ActiveRecord::Base
  belongs_to :event
  has_many :tests, dependent: :destroy
end

class Test < ActiveRecord::Base
  belongs_to :week
end

这个观点:

=form_for @event do |e|
  %h3 Event
  =render 'form', e: e # This partial contains the general data of the Event.

  %h3 Weeks

  %table
    %thead
      %th Start
      %th End
      %th X
    %tbody
      =e.fields_for :weeks do |w|
        =render 'week_fields', w: w
  =link_to_add_fields 'Add Week', e, :weeks # Custom helper that adds the fields of the week to the end of the table via JavaScript.

  %h3 Tests

  -@weeks.each do |week|
    %h5=week.start # Prints the 'start' of the Week.
    %table
      %thead
        %th Start
        %th End
        %th X
      %tbody
        = e.fields_for :tests, week.tests do |t|
          =render 'test_fields', t: t, s: week.id
    =link_to_add_fields 'Add Test', e, :tests, parent: week.id

这适用于添加事件和周,但当我尝试添加新测试时,我收到一条错误消息:

无法修改关联&#39;事件#test&#39;因为源反射类&#39;测试&#39;与周&#39;相关联via:has_many。

我理解这是由于我在视图中获得关联的方式,但我不太清楚应该如何使用它们。

这是我使用上述link_to_add_fields帮助的代码:

def link_to_add_fields(name, f, association, parent: 0)
  new_object = f.object.send(association).klass.new
  id = new_object.object_id
  fields = f.fields_for(association, new_object, child_index: id) do |builder|
    render(association.to_s.singularize + "_fields", f: builder, s: parent)
  end
  link_to(name, '#', class: 'btn btn-default add_fields', id: "add_#{association}", data: {id: id, association: association, fields: fields.gsub("\n", "")})
end

帮助程序生成的代码随后通过JavaScript引入到表单中。它是Railcasts剧集中使用的版本的修改版本。

这是我在控制器上使用的限制参数:

def event_params
  params.require(:event).permit(:name, :start, :end, :place,
                                 tests_attributes: [:id, :name, :date, :time, :week_id],
                                 weeks_attributes: [:id, :start, :end, :_destroy])
end

这适用于编辑现有测试的数据,但不适用于帮助程序生成的新数据。我正在阅读(在我的情况下)tests_attributes应该在week_attributes内,因为我试图修改的测试属于到周。像这样:

def event_params
  params.require(:event).permit(:name, :start, :end, :place,
     weeks_attributes: [:id, :start, :end, :_destroy, test_attributes: [:id, :name, :date, :time, :week_id]])
end

我不知道如何使表单遵循此关联(或者如果这实际上是一个解决方案)。我知道Test无法修改,因为它被拉为只读,但我不确定如何在视图中排列关联,以便在我更新Event时可以保存它。

非常感谢任何指针。

2 个答案:

答案 0 :(得分:2)

这有点棘手,但我明白了。这是修改 内的内容的问题。

我通过使用类似的东西来实现它:

%h3 Tests

-@weeks.each do |week|
  =e.fields_for :weeks, week do |w|
    %h5=week.start # Prints the 'start' of the Week.
    %table
      %thead
        %th Start
        %th End
        %th X
      %tbody
        = w.fields_for :tests, week.tests do |t|
          =render 'test_fields', t: t, s: week.id
    =link_to_add_fields 'Add Test', w, :tests, parent: week.id

诀窍是让为Test生成的字段位于为Week生成的字段内。首先,我添加了e.fields_for :weeks, week do |w|,表示以下字段属于到Weeks,然后我使用之前的each循环将数据限制为当前选定的Week。

接下来,我在w中使用了新的fields_for关联进行测试。这会使渲染生成的每个字段都采用“event [weeks_attributes] [ week_id ] [tests_attributes] [ test_id ]”的格式,这就是我所期待的对于我的控制器中的参数。

同样在link_to_add_fields中进行,我更改属于事件的e关联,属于Weeks的w。这也会改变使用我之前描述的格式通过JavaScript生成的新记录的格式。

最后,我不得不改变控制器中预期的格式。我使用单数形式test,它必须更改为复数,因为可以在表单中添加多个记录。所以我最终得到了这样的东西:

def event_params
  params.require(:event).permit(:name, :start, :end, :place,
     weeks_attributes: [:id, :start, :end, :_destroy, tests_attributes: [:id, :name, :date, :time, :week_id]])
end

它有效!

答案 1 :(得分:0)

我认为你应该在这里使用复杂的嵌套表单结构来添加一周的测试。 e.fields_for :tests应位于e.fields_for :weeks块内,以便进行正确的关联。

你可以从这里获得想法Deep Nested Rails 4 Form