通过remote_link的嵌套属性的collection.build在提交表单时不会创建参数

时间:2010-11-10 12:09:26

标签: ruby-on-rails

我有以下型号:

class Activity < ActiveRecord::Base
  has_many  :clientships, :dependent => :destroy, :after_add => :default_client_info
  accepts_nested_attributes_for :clientships, :allow_destroy => true
end

在我的控制器中,如果我执行以下操作

  def new
    @activity = IndividualActivity.new(params[:activity])
    @activity.clientships.build(:client => Client.first)
    ...
  end

然后保存表单,它会创建相关的参数并成功提交。

但是,如果我选择通过远程链接呼叫以下内容

@activity.clientships.build(:client => Client.last)

视图使用新的客户记录更新,但是当我提交表单时,不会为第二个嵌套属性创建参数[:activity]。 (为什么不呢? !?)

这是观点:

%h1 Create a new Activity

- form_for @activity do |f|
  %div
    = render "activities/client_selector", :f => f

  %div
    = f.submit "Save!"

这是remote_link的控制器操作

  def add_client

    @activity = IndividualActivity.new(session[:individual_activity])

    # Refresh client
    @activity.clientships.build(:client => Client.find(params[:client_id]))

    respond_to do |format|
      format.js
    end
  end

这是add_client.html.js:

page.replace_html "selected_clients", :partial => 'activities/clients'

这是活动/客户部分:

- form_for @activity do |f|
  - f.fields_for :clientships do |client_f|
    %tr
      %td= client_f.hidden_field :client_id
      %td= client_f.object.client.full_name

有谁知道如何进一步解决这个问题?我的调试似乎已经走到了尽头......有一点需要注意,以下是form_for的双重用法用于new.html.haml和activities / clients partial(这有问题吗?)

- form_for @activity do |f|

我在rails v2.3.5

由于

1 个答案:

答案 0 :(得分:1)

您询问有关调试的信息,因此第一步可能是查看服务器日志(log / development.log)。

你应该看到“params”哈希。 也许你的参数包含“activity”=&gt; {“client_id”=&gt; ..}而不是“client_id”=&gt; ..?

另请查看生成的HTML页面 - 使用Firebug或只使用浏览器的“查看源”方法。特别要注意输入名称。

如果一切正常,请在您的操作中添加一些调试调用,并查看development.log中的某些数据库活动 - SQL查询看起来像是在执行您想要的操作吗?

在您的问题中,没有“保存”方法。 'build'方法不保存创建的记录。也许这是你的问题?

def add_client
  logger.debug "Creating Activity"
  @activity = IndividualActivity.new(session[:individual_activity])
  logger.debug "Building clientship"
  # Refresh client
  @activity.clientships.build(:client => Client.find(params[:client_id]))
  logger.debug "@activity = #{@activity.inspect}"
  # Maybe you were missing this part of code?
  logger.debug "Saving @activity"
  @activity.save! # use a ! to easily see any problems with saving.
          # Remove in production and add a proper if
  logger.debug "Saved. @activity = #{@activity.inspect}"
  respond_to do |format|
    format.js
  end
end

您应该创建一个功能测试(如果您还没有),并确保如果您发送适当的参数,您的操作将按预期工作。

测试会缩小您的搜索范围。如果测试失败,您知道操作中存在问题。如果测试没问题,您需要确保正确发送参数,并且您可能在视图中遇到问题。

<强>更新: 你说你在页面上有两个表格。这可能是问题,因为一次只能发送一个表格。否则,它需要以一种可以在一个请求中发送两个请求的方式工作。

第一件事(在所有类似问题中都很有用):验证您的网页是否具有正确的HTML结构 - 例如http://validator.w3.org将是一个良好的开端。尝试使代码验证。我知道有些人将“绿色”状态视为无法实现的掌握,但实际上并非如此困难。使用有效的代码,您可以确定浏览器真正理解您的意思。

第二:将所有输入放在一个表单中。您有嵌套属性的问题。首先,尝试手动插入名称为<input name="activity[clientship_attributes][0][name]" value="John"/>的输入,对于现有客户端,确保输入名称为activity[clientship_attributes][0][id]。 这是处理嵌套属性的方式。

您的视图可能会自动创建此类字段。这个结构应该是你需要的:(它在我的一个旧的项目中使用rails 2.x,我刚刚用你使用的名称替换了名称)

<% form_for(@activity) do |f| %>
  <p><%= f.text_field :activity_something %></p>

  <% @activity.clientships.each do |clientship| %>
    <% f.fields_for :clientships, clientship do |cform| %>
      <p><%= cform.text_field :name %></p>
      <p><%= cform.text_fiels :something %></p>
    <% end %>
  <% end %>
<% end %>

如果你真的想在那里使用部分,请不要在partial中创建新表单。仅使用上述代码的部分。

要将变量传递给partial,请在调用render的位置使用:locals属性:partial:

<%= render :partial => 'clientship', :locals => {:form => f} %>

然后,在您的部分内容中,您可以使用局部变量form,在局部变量f之外使用:locals => {:f => f}。当然,您可以将变量映射到相同的名称:{{1}}