项目控制器索引方法执行两次丢失本地或实例变量设置

时间:2015-11-22 05:16:26

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

更新:我已将此发布到github jquery-datatables-rails,因为它似乎是该gem的一个问题,或者更可能是我对它的使用。我在这里发布更新的副本以及更多描述以寻求帮助。请注意,当respond_to块执行两次时,数据表代码仅在块的第二次执行时执行。

我正在尝试将名为my_view的变量传递给Items Controller索引方法,以便我可以有选择地显示结果。当前代码工作,排序......最后,视图不会被维护,结果表中的任何操作(例如滚动)都会导致表格恢复显示所有项目而不是所需的选择。

基本问题是索引方法总是在单击按钮时执行两次。第一次正确设置my_view变量。第二次,总是零。 jquery-datatables-rails gem在两个pass上执行,可能涉及。几乎看起来我得到两个不同的交易。我甚至尝试过实例变量,在第二遍中它们也是零。我不明白这种情况发生的原因或原因。

To" fix"这个问题,我在第一次传递期间设置了session [:my_view],然后在第二次传递时不再设置它。在ItemsDatatable.new执行期间,我必须清除会话[:my_view],否则它将被保留用于下一个事务,给出不正确的结果。但是,这导致了我所说的问题,即对视图的任何更改(例如滚动)都会导致返回显示所有项目而不是所需的选择。

奇怪的是,我似乎没有任何其他控制器方法存在这种异常,或者至少没有注意到它。有人能告诉我为什么索引方法执行两次,以及我如何解决这个问题?谢谢!

EDIT UPDATE:我在admin命名空间中有另一个控制器,它使用带有HTML / JSON选项的respond_to。它也被执行两次,所以似乎可能(?)是相关的。丢失所有变量并第二次执行它仍然是一种奇怪的行为,但我不知道。是否相关,我该如何解决?感谢...

以下是我的按钮:

  <%= link_to 'My Items', items_path(my_view: current_associate.id), class: 'btn btn-primary kc-wide' %>
  <%= link_to 'All Items', items_path(my_view: "all"), class: 'btn btn-primary kc-wide' %>

使用索引方法的Items Controller:

class ItemsController < ApplicationController

  def index
    session[:my_view] ||= params[:my_view]
    respond_to do |format|
      format.html
      format.json { render json: ItemsDatatable.new(view_context) }
    end
  end
end

相关路线,以防万一?

                  POST     /items_index(.:format)                items#index
        items GET      /items(.:format)                      items#index
                  POST     /items(.:format)                      items#create
new_item GET      /items/new(.:format)                  items#new
edit_item GET      /items/:id/edit(.:format)             items#edit
        item GET      /items/:id(.:format)                  items#show
                PATCH    /items/:id(.:format)                  items#update
                PUT      /items/:id(.:format)                  items#update
                DELETE   /items/:id(.:format)                  items#destroy

Rails数据表代码是:

class ItemsDatatable < ApplicationController

  before_action :check_if_associate

  delegate :params, :h, :link_to, :edit_item_path, :new_item_path, :location, to: :@view

  def check_params(params)
    # When using the .json suffix in URI, need to stub params so that I can see that JSON information
    params[:draw] = 1 if params[:draw].blank?
    params[:columns] = Array.new(1, {data: 0, name: '', searchable: true, orderable: true, search: {value: '', regex: false}}) if params[:columns].blank?
    params[:order] = Array.new(1, {column: 0, dir: 'asc'}) if params[:order].blank?
    params[:start] = 0 if params[:start].blank?
    params[:length] = 10 if params[:length].blank?
    params[:search] = {value: '', regex: false} if params[:search].blank?
  end

  def initialize(view)
    @view = view
    check_params(params)
    @view
  end

  def as_json(options = {})
    {
        draw: params[:draw].to_i,
        recordsTotal: Item.count,
        recordsFiltered: items.total_entries,
        data: data
    }
  end

  private

  def data
    todays_date = Time.zone.now.to_date
    items.map do |item|
      status = item.status
      # If current associate has it, show where it is.
      if item.checkedout?(@view.current_associate)
        status = "#{item.status}-#{item.lastloc}"
      end
      # If it's checked out but someone else has it, show who has it.
      if item.not_available? and !item.checkedout?(@view.current_associate)
        status = "#{item.status}-#{item.location}"
      end
      # Override the above if in return status, just showing that.
      status = item.status == "Rtn" ? "Rtn" : status
      odometer = item.odometer.to_s.gsub(/(\d)(?=(\d{3})+(?!\d))/, "\\1,")
      msrp = item.msrp.to_s.gsub(/(\d)(?=(\d{3})+(?!\d))/, "\\1,")
      age_date = item.age_date.nil? ? todays_date : item.age_date.to_date
      [
          link_to(item.stock_number, edit_item_path(item)),
          ERB::Util.h(item.year),
          ERB::Util.h(item.make),
          ERB::Util.h(item.model),
          ERB::Util.h(item.color),
          ERB::Util.h(status),
          ERB::Util.h(odometer),
          ERB::Util.h(msrp),
          ERB::Util.h((todays_date - age_date).to_i)
      ]
    end
  end

  def items
    @items ||= fetch_items
  end

  def fetch_items
    items = Item.order("#{sort_column} #{sort_direction}")
    items = items.includes(:item_location, item_location: [:locator])
    items = items.includes(:key, key: [:key_location])
    items = items.page(page).per_page(per_page)
    unless @view.session[:my_view].blank? || @view.session[:my_view] == "all"
      associate = Associate.find(@view.session[:my_view]).name
      associate = associate.gsub(/'/, "''") # .gsub(/'/, "\\\\\'")
      items = items.where("clshadow = \'#{associate}\'")
    end
    @view.session[:my_view] = nil
    if params[:search][:value].present?
      items = items.where("stock_number ilike :search or yrshadow ilike :search or mkshadow ilike :search or mdshadow ilike :search or coshadow ilike :search or status ilike :search", search: "%#{params[:search][:value]}%")
    end
    items
  end

  def page
    params[:start].to_i/per_page + 1
  end

  def per_page
    params[:length].to_i > 0 ? params[:length].to_i : 10
  end

  def sort_column
    columns = %w[stock_number yrshadow mkshadow mdshadow coshadow status odometer msrp age_date]
    columns[params[:order][0][:column].to_i]
  end

  def sort_direction
    params[:order][0][:dir] == "desc" ? "desc" : "asc"
  end

end

相关的JavaScript代码:

var itemstable = $('#itemstable').DataTable({
    responsive: true,
    autoWidth: false,
    pagingType: 'full',
    jQueryUI: true,
    processing: true,
    serverSide: true,
    ajax: {
        url: 'items_index.json',
        type: 'POST',
        contentType: 'application/json',
        dataType: 'json',
        data: function(d) {
            return JSON.stringify(d);
        }
    },
    columns: [null, null, null, null, null, null,
        {className: 'dt-right'},
        {className: 'dt-right'},
        {className: 'dt-right'}
    ]
});

观点:

<div class="span9">
  <p>
  <table id="itemstable" class="display dt-responsive no-wrap table-striped"  width="80%">
    <thead>
    <tr>
      <th class="all">Stock No.</th>
      <th class="all">Year</th>
      <th class="all">Make</th>
      <th class="min-tablet">Model</th>
      <th class="min-tablet">Color</th>
      <th class="all">Status</th>
      <th class="desktop">Mileage</th>
      <th class="desktop">MSRP</th>
      <th class="desktop">Aged</th>
    </tr>
    </thead>
    <tbody>
    </tbody>
  </table>
  <%= link_to 'My Items',  items_path(my_view: current_associate.id),
              class: 'btn btn-primary kc-wide' %>
  <%= link_to 'All Items', items_path(my_view: "all"),
              class: 'btn btn-primary kc-wide' %>
  <%= link_to 'Recent Items', x_logs_path,
              class: 'btn btn-primary kc-wide' %>
  <%= link_to 'Home', '/', class: 'btn btn-primary kc-wide' %>
</div>

2 个答案:

答案 0 :(得分:0)

在第一次传递期间,gem似乎独立执行,而不将控制权转移到提供的代码,以便设置包含所有所需变量的参数列表。然后它似乎强制重新加载以根据需要使用参数列表启动该过程。我假设这是在第一次和第二次通过期间检查变量。在此过程中,它会忘记任何其他变量,但我不认为它应该这样做。

在任何情况下,我都必须使用会话变量来维护此重新加载期间的状态。我按如下方式更改了控制器索引,然后在我的数据表控制器中清除了会话[:my_view]的清除。

  def index
    unless params[:my_view].blank?
      session[:requested_view] = params[:my_view]
    end
    session[:my_view] = session[:requested_view]
    respond_to do |format|
      format.html
      format.json { render json: CarsDatatable.new(view_context) }
    end
  end

答案 1 :(得分:0)

试试这个: -

def index
    session[:my_view] = params[:my_view] unless request.xhr?
    respond_to do |format|
        format.html
        format.json { render json: ItemsDatatable.new(view_context) }
    end
end