Category : Ruby

RailsとjQueryでインクリメンタルサーチの処理を書いてみたのでまとめました。
これを利用したものをshot ideaというサービスで実装していたりします

目次

本エントリの前提

  • インクリサーチは、ポスト(Model:Post)のタイトル(title)を検索
  • json形式でデータを受け取り、JSでページを更新

ルーティング

今回はposts/newページ内で利用するので:postsのcollection内に入れました。

#config/routes.rb
resources :posts do
	collection do
		get 'search', :action => :search
		# posts/search
	end
end

Controller

params[:q]に、クエリのデータが入っています。
Model:Postのtitleから、クエリの文字列を含むものを最大3件取得しています。

#app/controllers/posts_controller.rb

def search
	raise unless params[:q]

	lists = []
	results = Post.where("title like ?", "%#{params[:q]}%").order('count DESC').limit(3)
	results.each do |result|
		lists.push({:title => result.title) if result.title
	end
	render :json => { :lists => lists, :result => "success"}
	return true

	rescue
	render :json => {:result => "error_search" }, :status => 400
end

JavaScript

検索枠にテキストを入力し、500ms経ったあとに1回ajax通信を行います。
onkeypressでイベントを発生させているため、文字入力を行う度にincSearch関数が実行されます。関数内でclearTimeoutを実行することで、関数実行時にタイマーがリセットされるため、関数の実行回数 = 通信の回数にはならないようにしています。

※ DOMの処理は省略
※ 実際は、エンターキーを押した時の分岐やonblurイベントも加えないと、思い通り動かないかも?

// application.js

// ajax処理
function incSearch(){
	// タイマーをストップ
	clearTimeout(incSearch.timeid);

	// setTimeout 500ms
	incSearch.timeid = setTimeout(function(){
		// inputに入力されているテキストを取得
		var query = tgtInput.value;
		if(query.length == 0) return false;

		// ajax処理
		jQuery.ajax({
			type : 'GET',
			url : '/posts/search',
			data : {
				q : query
			},
			timeout : 1500,
			success:function(data){
				if(data.result != "success") return false;
				changeDom(data.lists);
			},
			error:function(){
				// エラー時の処理をここに書く
				return false;
			}
		});

	},500);

};
incSearch.timeid = "";

// DOMの変更
// 引数listsに検索結果が入っている
function changeDom(lists){
	if(lists.length == 0) return false;
	// ここにDOMを書き換える処理を書く
};

// ターゲットとなるinputタグにイベント追加
var tgtInput = document.getElementById('tgtInput');
tgtInput.onkeydown = incSearch;