Метод индекса контроллера элементов выполняется дважды, теряя настройки локальной переменной или переменной экземпляра.

Обновление: я разместил это на github jquery-datatables-rails, так как это похоже на проблему с этим драгоценным камнем или, что более вероятно, с моим использованием. Я также размещаю обновленную копию здесь с дополнительным описанием, чтобы попросить о помощи. Обратите внимание, что хотя блок response_to выполняется дважды, код с данными выполняется только при втором выполнении блока.

Я пытаюсь передать переменную с именем my_view методу индекса контроллера элементов, чтобы я мог выборочно отображать результаты. Текущий код работает, вроде... В конце концов, представление не сохраняется, и любое действие в результирующей таблице, например прокрутка, приводит к тому, что таблица возвращается к отображению всех элементов вместо желаемого выбора.

Основная проблема заключается в том, что метод index всегда выполняется дважды при каждом нажатии кнопки. В первый раз переменная my_view установлена ​​правильно. Второй раз всегда ноль. Гем jquery-datatables-rails выполняется на обоих проходах и, вероятно, задействован. Кажется, что я получаю две разные транзакции. Я даже пробовал переменные экземпляра, и они также равны нулю во время второго прохода. Я не понимаю, как и почему это происходит.

Чтобы «исправить» эту проблему, я устанавливаю session[:my_view] во время первого прохода, а затем не устанавливаю его снова при втором проходе. Затем во время выполнения ItemsDatatable.new я должен очистить session[:my_view], иначе он будет сохранен для следующей транзакции, дающей неверные результаты. Однако это приводит к проблеме, о которой я говорил, в том, что любое изменение в представлении, такое как прокрутка, приводит к возврату к отображению всех элементов вместо желаемого выбора.

Любопытно, что у меня нет других методов контроллера с такой аномалией, или, по крайней мере, я этого не заметил. Может ли кто-нибудь сказать мне, почему метод индекса выполняется дважды и как я могу решить эту проблему? Благодарю вас!

РЕДАКТИРОВАТЬ ОБНОВЛЕНИЕ: у меня есть еще один контроллер в пространстве имен администратора, который использует response_to с параметрами HTML/JSON. Он также выполняется дважды, поэтому кажется, что это может (?) быть связано. Все еще кажется странным поведение, чтобы потерять все переменные и выполнить его во второй раз, но я не знаю. Связано ли это и как я могу это решить? Спасибо...

Вот мои кнопки:

  <%= 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 с методом index:

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>

person Richard_G    schedule 22.11.2015    source источник
comment
Я бы поискал что-то в вашем Javascript, вызывающее это - на самом деле это не может быть проблема с контроллером.   -  person Frederick Cheung    schedule 22.11.2015
comment
@FrederickCheung Я согласен и публикую это на форуме jquery-datatables-rails. Спасибо.   -  person Richard_G    schedule 22.11.2015
comment
@FrederickCheung Я разместил вопрос на этом форуме и заменил весь вопрос здесь дополнительной информацией и согласился с тем, что, вероятно, я использовал гем jquery-datatables-rails ...   -  person Richard_G    schedule 22.11.2015


Ответы (2)


Попробуй это:-

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
person user3506853    schedule 23.11.2015
comment
Это работает, чисто и кажется правильным способом справиться с этим. Хороший улов. Пожалуйста, уточните аргументацию, и я соглашусь. - person Richard_G; 24.11.2015
comment
Есть ссылки Мои товары и Все товары, на которых вы устанавливаете значение переменной my_view. Оба являются html-запросами. И когда пользователь нажимает на любую ссылку, он вызывает метод index и устанавливает значение my_view в сеансе. На той же странице также вызывается ajax для таблицы данных, которая вызывает тот же метод индекса, что и js. Но этот запрос js не устанавливает значение переменной my_view. Поэтому я добавил условие, что значение переменной my_view устанавливается в переменной сеанса, когда это html-запрос. Таким образом, запрос js будет принимать значение переменной my_view, которое доступно в сеансе. - person user3506853; 24.11.2015

Похоже, гем выполняется самостоятельно, без передачи управления предоставленному коду, во время первого прохода, чтобы настроить список параметров со всеми нужными переменными. Затем появляется принудительная перезагрузка, чтобы инициировать процесс со списком параметров по желанию. Я предполагаю это, просматривая переменные во время первого и второго проходов. Во время этого процесса он забывает любые другие переменные, хотя я не думаю, что он должен это делать.

В любом случае, я должен использовать переменные сеанса для сохранения состояния во время этой перезагрузки. Я изменил индекс контроллера следующим образом, а затем исключил очистку session[:my_view] в моем контроллере datatables.

  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
person Richard_G    schedule 22.11.2015