読者です 読者をやめる 読者になる 読者になる

Railsでページング位置を覚えておく方法

Ruby

RailsでScaffoldの作ったコントローラーに WillPaginate等で一覧のページングを追加したアプリを作る事がよくあると思いますが、ページングで2ページ目を表示し、そこで編集し戻ってくると一覧は1ページ目に戻ってしまいます。

編集しても2ページ目に戻ってこれるようにするのに、皆さんはどうしていますか?

class TodosController < ApplicationController
  def index
    @todos = Todo.find(:all, :order => :due)
  end

  def show
    @todo = Todo.find(params[:id])
  end

  def edit
    @todo = Todo.find(params[:id])
   end

  def update
    @todo = Todo.find(params[:id])

    if @todo.update_attributes(params[:todo])
      flash[:notice] = 'Todo was successfully updated.'
      redirect_to(@todo)
    else
      render :action => "edit"
    end
  end

  ....

一覧表示のページ位置を覚え、表示/編集後に一覧のページに戻る方法には大きく

  1. パラメター、hidden等でページ位置を表示/編集処理で持ち回る
  2. ページ位置をセッションに覚えておき、一覧表示に戻った際にセッション中のページ位置を使う

などがあると思います。
1の方法は結構面倒ですし、表示/編集処理が本質的でなページ位置などの処理をするのは良くないと思います。
2の方法は簡単に実装できるのですが、セッションを無効にするタイミングの考慮、コントローラが複数ある場合のセッションを分けたりする必要があります。

今、作っているアプリでは 2の方式なのですが、Railsflashを組み合わせてみました。flashは次のページでの表示まで有効なセッションなので、自動的に消えてくれるのが良い点です。


下のコードの様に、一覧に戻る際にページ位置をflashを使って渡すのがポイントです。一覧の表示後はflashは消えてしまうので、他のコントロラーや他のアクションに行って戻ってきた場合は、記憶したページ位置は使われません。

class TodosController < ApplicationController
  def index
    @todos = Todo.paginate(:page => flash[:page] ? flash[:page] : params[:page],
                           :order => :due, :per_page => 5)
    session[:last_page] = @todos.current_page
  end

  def show
    @todo = Todo.find(params[:id])
    flash[:page] = session[:last_page]
  end

  def edit
    @todo = Todo.find(params[:id])
    flash[:page] = session[:last_page]
  end

  def update
    @todo = Todo.find(params[:id])

    if @todo.update_attributes(params[:todo])
      flash[:notice] = 'Todo was successfully updated.'
      redirect_to(@todo)
    else
      render :action => "edit"
    end
  end
  ....

もちろん、URLを手入力して、表示等を行うと一覧の意図しないページに戻る可能性もありますが・・・