1.) Install the gem in your Gemfile:

gem 'will_paginate', '~> 3.1.0'

In your routes.rb file you must have something like:

namespace :api, defaults: {format: :json} do

namespace :v1 do

post '/articles/search/'=>'articles#search'

end

end

save and restart your rails server.

2.) Set up the normal will_paginate query in your Rails controller:

# file: app/controllers/api/v1/articles_controller.rb def search

myparams = { page: params[:page], :per_page: params[:per_page] } articles = Articles.where("description ILIKE #{params[:term]}").paginate(myparams)



response = {articles: articles, total: articles.total_entries} return render json: response

end

NOTE: If you are filtering your params with:

params.require(:article).permit(:title…

add the symbols, :term, :page and :per_page.

3.) Test your request inside the Rails console:

app.get '/'

token = app.session[:_csrf_token]

app.post '/api/v1/articles/search', params: {article:{term: 'lorem ipsum', page: 2, per_page: 9}}, headers: {'X-CSRF-Token' => token}

app.response.body

4.) Rails, is ready, now the front-end part. The action that loads the response:

// file: REACT/actions/articles.jsx require('es6-promise').polyfill();

require('isomorphic-fetch'); export const SEARCH_ARTICLES = 'SEARCH_ARTICLES'; export function searchArticles(term, page, per_page) {

return function (dispatch) {

let data = {

method: 'POST',

credentials: 'same-origin',

mode: 'same-origin',

body: JSON.stringify({article: {term: term,

page: page,per_page: per_page}}),

headers: {

'Accept': ‘application/json’,

'Content-Type': ‘application/json’,

'X-CSRF-Token': $(‘meta[name=”csrf-token”]’).attr(‘content’)

}

}

return fetch(‘/api/v1/articles/search/’, data)

.then(response => response.json())

.then(json => dispatch(setSearch(json)));

}

}; function setSearch(SearchArrayProp) {

return {

type: SEARCH_ARTICLES,

SearchArrayProp

}

};

5.) Your Redux reducer is simple:

// file: REACT/reducers/my_rdcr.jsx

import { SEARCH_ARTICLES} from '../actions/articles' const my_rdcr = (state = {}, action) => {

switch (action.type) {

case SEARCH_ARTICLES:

return Object.assign({}, state, {

SearchArrayProp: action.SearchArrayProp.articles,

TotalNumberProp: action.SearchArrayProp.total

}); }

} export default my_rdcr;

6.) Finally, our React component:

// file: REACT/components/ArticlesSearchComponent.jsx

'use strict' import React, { PropTypes, Component } from ‘react’

import { Link, browserHistory, withRouter } from ‘react-router’

import { connect } from ‘react-redux’ import { Button } from ‘react-bootstrap’

import * as ArticlesActionCreators from ‘../actions/articles’ class ArticlesSearchComponent extends Component {

constructor(props) {

super(props)

this.state = {

term: '',

page: 1,

rows_per_page: 10

}

this.loadArticles = this.loadArticles.bind(this);

this.initPageNumbers = this.initPageNumbers.bind(this);

this.getPage = this.getPage.bind(this);

} loadArticles(){

let action = ArticlesActionCreators.searchArticles( this.state.term, this.state.page, this.state.rows_per_page);

this.props.dispatch(action);

} handleChange(event){

this.setState({term:event.target.value});

} getPage(page) {

this.setState({page: page});

let self = this;

setTimeout(function(){ self.loadArticles() ; }, 1000);

} initPageNumbers(){

let total_rows = parseInt(this.props.TotalNumberProp);

let page = 1;

let rows = [];

for(var x = 0; x < total_rows; x += this.state.rows_per_page){

rows.push(page);

page++;

}

return rows;

} render() {

let rows = this.initPageNumbers();

return (

<div id=”responsive”>

<div>

<form>

<label htmlFor=”term”>Search for articles:</label>

<input className="form-control" name=”term” value={this.state.terms} onChange={this.handleChange.bind(this)} />

<Button onClick={this.loadArticles.bind(this)}>Search</Button>

</form>

</div>

{ this.props.SearchArrayProp.length ? null : <div>No matches</div> }

<div className="container_div">

{this.props.SearchArrayProp.map((article, i) =>

<div key={i}> <b>{i+1}.-</b>: {article.title} {article.id}

</div>

)}

</div>



<div>

<ul className="pagination">

{rows.map((r) =>

<li key={r}>

<a href={"#"+r} onClick={() => this.getPage(r)}>{r}</a>

</li>

) }

</ul>

</div>

</div>

);

}

} ArticlesSearchComponent.propTypes = {

SearchArrayProp: PropTypes.array,

TotalNumberProp: PropTypes.number

} ArticlesSearchComponent.defaultProps = {

SearchArrayProp: [],

TotalNumberProp: 0

} const mapStateToProps = (state) => {

return {

SearchArrayProp: state.my_rdcr.SearchArrayProp,

TotalNumberProp: state.my_rdcr.TotalNumberProp

}

} // binding React-Router-Redux

export default withRouter(connect(mapStateToProps)(ArticlesSearchComponent));

And there you have! Pagination with React and Ruby on Rails. Note that I’m using the CSS “pagination” class from Bootstrap.

You can test your request with this: