Rails服务器提升"回收对象"有时当object_id对象实例时出错

时间:2016-04-18 15:53:37

标签: ruby-on-rails ruby ajax nested-forms

我的问题是在ajax的方式添加{strong>动态的部分内容时发生了Rails。异步请求是在input对象的事件Node发生时生成的,并且它可以正常工作。她将stock_ingredient_f.object_id属性中定义的data-action发送给控制器,并且根据部分form_parent定义了辅助方法_stock_ingredient_fields.haml

这是我的表格。

= form_for @stock_ingredient, remote: true do |stock_ingredient_f|
  .field
    = stock_ingredient_f.label "Enable/disable keyboard"
    = check_box :keyboard, :handler

  .field
    = stock_ingredient_f.label "Barcode"
    = text_field :ingredient, :barcode, value: stock_ingredient_f.object.ingredient.try(:barcode), class: "barcode", :'data-action' => ingredient_async_path(form_parent_object_id: stock_ingredient_f.object_id)

  - if @stock_ingredient.stock.present?
    .field
      = stock_ingredient_f.label "Stock"
      = stock_ingredient_f.number_field :stock
      %span.brown-color
        = "(#{@stock_ingredient.ingredient.net_weight_unit})"

这是应该动态加载的部分内容。

.ingredient-data

  .field
    %dl
      .line
        %dt
          Ingredient:
        %dd
          = "#{@ingredient.name}"

      .line
        %dt
          Stock:
        %dd.stock
          = "#{MeasurementUnits.humanize_for @ingredient.stock_ingredient.stock, resolve_unit_type(@ingredient.net_weight_unit)}"

  .field
    / the problem is raised here
    = form_parent.label "Stock"
    = form_parent.number_field :stock
    %span.brown-color
      = "(#{@ingredient.net_weight_unit})"

  .field
    = form_parent.submit "Save"
    = form_parent.button "Cancel", type: :reset

这是我的application_controller.rb,其中定义了方法form_parent

class ApplicationController < ActionController::Base
  respond_to :html, :js

  # Prevent CSRF attacks by raising an exception.
  # protect_from_forgery with: :exception

  # when will has it login, change this line
  protect_from_forgery with: :exception, if: Proc.new { |c| c.request.format != 'application/json' }
  protect_from_forgery with: :null_session, if: Proc.new { |c| c.request.format == 'application/json' }

  def form_parent
    ObjectSpace._id2ref(params[:form_parent_object_id].to_i) if params[:form_parent_object_id]
  end
  helper_method :form_parent

  def root
    render "layouts/application", layout: false
  end

  protected

    def id
      params[:id]
    end

    def redirect_for_async_request location
      render js: "window.location='#{location}'"
    end

    def alert message
      render js: "window.alert('#{message}')"
    end

    # def no_cache
    #   if Rails.env.development?
    #     response.headers["Cache-Control"] = "no-cache, must-revalidate, max-age=0"
    #   end
    # end

end

刷新页面并再次触发请求时,服务器会说:ActionView::Template::Error (0x002ac5927b9058 is recycled object)可能会引用ObjectSpace._id2ref的响应。 我相信收集了垃圾收集器。

UPDATE application_controller.rb

def form_parent
  @@form_parent
end

def store_form object
  @@form_parent = object
end
helper_method :form_parent, :store_form

形式

= form_for @stock_ingredient, remote: true do |stock_ingredient_f|
  - store_form stock_ingredient_f

  .field
    = stock_ingredient_f.label "Enable/disable keyboard"
    = check_box :keyboard, :handler

  .field
    = stock_ingredient_f.label "Barcode"
    = text_field :ingredient, :barcode, value: stock_ingredient_f.object.ingredient.try(:barcode), class: "barcode", :'data-action' => ingredient_async_path

  - if @stock_ingredient.stock.present?
    .field
      = stock_ingredient_f.label "Stock"
      = stock_ingredient_f.number_field :stock
      %span.brown-color
        = "(#{@stock_ingredient.ingredient.net_weight_unit})"

2 个答案:

答案 0 :(得分:1)

此错误表示您正在尝试访问已被垃圾收集的对象,您可能已怀疑。发生这种情况是因为对象id来自上一次,并且一旦id被发送到浏览器,就不再存在对该对象的引用,因此ruby清理了该对象。

尽管可能并非总是如此,但最好将每个请求视为在新的单独ruby进程中运行。如果要在请求之间“传递”数据,则必须将其发送到客户端(如果您不介意更改数据)或将其存储在会话中,或将其存储在数据库中。你不能像在这里那样传递物体。

答案 1 :(得分:0)

您怀疑是正确的 - 具有该object_id的对象已被垃圾收集。我不确定你为什么要这样做,但这听起来真的很糟糕。我不完全清楚form_parent是什么(FormBuilder实例?)但是猜测你应该传递数据库中对象的id,从数据库中获取对象并使用它来获得一个新的{来自FormBuilderform_for的{​​1}}实例。

即使您可以使当前的方法工作,它也会限制您使用单个rails实例,而任何严重的应用程序部署都会使用分布在2个或更多服务器上的多个实例。