使用带有form_for的MongoMapper EmbeddedDocument的命名空间嵌套资源

时间:2012-11-01 18:51:47

标签: namespaces ruby-on-rails-3.2 mongomapper form-for nested-resources

我正在提交一个表单,该表单为子资源及其父资源id发送子资源的id值。我不知道如何让表单提交停止将子ID复制为父资源的id。

技术堆栈:

  • Rails 3.2.8
  • MongoMapper
  • 简单表格(虽然它包装的库存形式也会出现同样的问题)

routes.rb的相关摘录:

namespace :mock do 
  resources :patients do
    resources :allergies
  end
end

我的模型在Mock::PatientMock::Patient::Allergy中定义。

在我的Allergy资源的视图部分_form.html.erb中,我有以下开头表单帮助用法(我使用简单表单,但库存form_for助手会出现相同的结果):

<%= simple_form_for [@mock_patient, @mock_allergy], :url => mock_patient_allergy_path(@mock_allergy),  do |f| %>

在呈现时,它正在提交到此路线:

/模拟/患者/:patient_id /过敏/:ID

所以我的allergies_controller.rb文件确实收到了更新操作(如果是编辑操作)。

但是,当我查看params时,params [:patient_id]与params [:id]相同。两者实际上都是正在编辑的特定嵌套过敏资源的id值。通过父资源(在这种情况下为患者)的上下文丢失。

所以,我打算在表单中包含一个隐藏字段:

<%= hidden_field_tag('patient_id', @mock_patient.id) if @mock_patient %>

当我在提交表单之前查看页面源代码时,我确实可以看到正确的 patient_id值。

似乎有一些内置的表单处理逻辑将父资源的id替换为子资源的id。

我的模型文件,使用Mongo Mapper:

class Mock::Patient
  include MongoMapper::Document
  # other Patient model keys here
  many :allergies, :class => Mock::Patient::Allergy 
end

class Mock::Patient::Allergy
  include MongoMapper::EmbeddedDocument
  # other Allergy model keys here
  belongs_to :patient, :class => Mock::Patient
end

回顾一下,我能够将表单标记设置为正确的路由,但受控制的接收的params哈希值会被抬高 - 丢失父资源上下文。

我尝试过的表单标记的其他变体,但无济于事:

<%= simple_form_for @mock_allergy, :url => mock_patient_allergy_path(@mock_allergy),  do |f| %>

<%= simple_form_for @mock_allergy, :html => { :class => 'form-horizontal' } do |f| %>

在上述两种情况下,生成的基本路由模板都很好,它到达了我的allergies_controller,但是当我去检查params[:patient_id]时,我得到的值不正确。它实际上是params[:id]的副本。

具体例子

我的表单标记行:

<%= simple_form_for @mock_allergy, :url => mock_patient_allergy_path(@mock_patient, @mock_allergy) do |f| %>

这会生成一个页面,当我查看来源时,报告:

<form accept-charset="UTF-8" 
action="/mock/patients/5092c815fdb5424df800000d/allergies/5092c815fdb5424df800001c" 
class="simple_form form-horizontal" 
id="edit_mock_patient_allergy_5092c815fdb5424df800001c" method="post" 
novalidate="novalidate"> 

但当它击中我的控制器时,谁想要根据on params [:patient_id]找到一个Mock :: Patient,它没有得到我期望的'5092c815fdb5424df800000d'值。在我的浏览器上,错误页面指示收到的参数是:

{ "patient_id"=>"5092c815fdb5424df800001c",
          "id"=>"5092c815fdb5424df800001c" }

这两个ID是相同的,其中存在问题。

连连呢?

1 个答案:

答案 0 :(得分:0)

解决:

在我的更新方法中,成功时脚手架的重定向是:

redirect_to @mock_allergy

而不是:

redirect_to mock_patient_allergy_path(@mock_patient, @mock_allergy)

所以,我受到了正确形成的路线的惩罚,但患有假病人_id。

我的另一个错误是,在对过敏症进行建模时,我应该使用embedded_in :patient代替belongs_to :patient行。

派生问题:

为什么@mock_allergyMock::Patient::Allergy的实例知道它是嵌套资源,无法生成包含正确patient_id的正确路径?