{"id":13878305,"url":"https://github.com/jbox-web/ajax-datatables-rails","last_synced_at":"2025-12-16T16:53:38.433Z","repository":{"id":3064836,"uuid":"4087393","full_name":"jbox-web/ajax-datatables-rails","owner":"jbox-web","description":"A wrapper around DataTable's ajax methods that allow synchronization with server-side pagination in a Rails app","archived":false,"fork":false,"pushed_at":"2025-01-29T00:51:27.000Z","size":700,"stargazers_count":595,"open_issues_count":48,"forks_count":228,"subscribers_count":29,"default_branch":"master","last_synced_at":"2025-04-28T17:03:00.363Z","etag":null,"topics":["datatables","jquery","jquery-datatables","rails","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jbox-web.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2012-04-20T14:27:19.000Z","updated_at":"2025-04-18T14:30:20.000Z","dependencies_parsed_at":"2024-06-18T13:38:45.490Z","dependency_job_id":"fae86ce1-9f66-411a-b784-630d754fe140","html_url":"https://github.com/jbox-web/ajax-datatables-rails","commit_stats":{"total_commits":576,"total_committers":46,"mean_commits":"12.521739130434783","dds":0.5954861111111112,"last_synced_commit":"53e732598be9061eaad99ad34d089b2f215b7438"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbox-web%2Fajax-datatables-rails","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbox-web%2Fajax-datatables-rails/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbox-web%2Fajax-datatables-rails/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jbox-web%2Fajax-datatables-rails/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jbox-web","download_url":"https://codeload.github.com/jbox-web/ajax-datatables-rails/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254029003,"owners_count":22002283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["datatables","jquery","jquery-datatables","rails","ruby"],"created_at":"2024-08-06T08:01:45.798Z","updated_at":"2025-12-16T16:53:38.383Z","avatar_url":"https://github.com/jbox-web.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# ajax-datatables-rails\n\n[![GitHub license](https://img.shields.io/github/license/jbox-web/ajax-datatables-rails.svg)](https://github.com/jbox-web/ajax-datatables-rails/blob/master/LICENSE)\n[![Gem](https://img.shields.io/gem/v/ajax-datatables-rails.svg)](https://rubygems.org/gems/ajax-datatables-rails)\n[![Gem](https://img.shields.io/gem/dtv/ajax-datatables-rails.svg)](https://rubygems.org/gems/ajax-datatables-rails)\n[![CI](https://github.com/jbox-web/ajax-datatables-rails/workflows/CI/badge.svg)](https://github.com/jbox-web/ajax-datatables-rails/actions)\n[![Code Climate](https://codeclimate.com/github/jbox-web/ajax-datatables-rails/badges/gpa.svg)](https://codeclimate.com/github/jbox-web/ajax-datatables-rails)\n[![Test Coverage](https://codeclimate.com/github/jbox-web/ajax-datatables-rails/badges/coverage.svg)](https://codeclimate.com/github/jbox-web/ajax-datatables-rails/coverage)\n\n**Important : This gem is targeted at DataTables version 1.10.x.**\n\nIt's tested against :\n\n* Rails: 7.1 / 7.2 / 8.0\n* Ruby: 3.1 / 3.2 / 3.3 / 3.4\n* Databases: MySQL 8 / SQLite3 / Postgresql 16 / Oracle XE 11.2 (thanks to [travis-oracle](https://github.com/cbandy/travis-oracle))\n* Adapters: sqlite / mysql2 / trilogy / postgres / postgis / oracle\n\n## Description\n\n\u003e [DataTables](https://datatables.net/) is a nifty jQuery plugin that adds the ability to paginate, sort, and search your html tables.\n\u003e When dealing with large tables (more than a couple of hundred rows) however, we run into performance issues.\n\u003e These can be fixed by using server-side pagination, but this breaks some DataTables functionality.\n\u003e\n\u003e `ajax-datatables-rails` is a wrapper around DataTables ajax methods that allow synchronization with server-side pagination in a Rails app.\n\u003e It was inspired by this [Railscast](http://railscasts.com/episodes/340-datatables).\n\u003e I needed to implement a similar solution in a couple projects I was working on, so I extracted a solution into a gem.\n\u003e\n\u003e Joel Quenneville (original author)\n\u003e\n\u003e I needed a good gem to manage a lot of DataTables so I chose this one :)\n\u003e\n\u003e Nicolas Rodriguez (current maintainer)\n\nThe final goal of this gem is to **generate a JSON** content that will be given to jQuery DataTables.\nAll the datatable customizations (header, tr, td, css classes, width, height, buttons, etc...) **must** take place in the [javascript definition](#5-wire-up-the-javascript) of the datatable.\njQuery DataTables is a very powerful tool with a lot of customizations available. Take the time to [read the doc](https://datatables.net/reference/option/).\n\nYou'll find a sample project here : https://ajax-datatables-rails.herokuapp.com\n\nIts real world examples. The code is here : https://github.com/jbox-web/ajax-datatables-rails-sample-project\n\n\n## Installation\n\nAdd these lines to your application's Gemfile:\n\n```ruby\ngem 'ajax-datatables-rails'\n```\n\nAnd then execute:\n\n```sh\n$ bundle install\n```\n\nWe assume here that you have already installed [jQuery DataTables](https://datatables.net/).\n\nYou can install jQuery DataTables :\n\n* with the [`jquery-datatables`](https://github.com/mkhairi/jquery-datatables) gem\n* by adding the assets manually (in `vendor/assets`)\n* with [Rails webpacker gem](https://github.com/rails/webpacker) (see [here](/doc/webpack.md) for more infos)\n\n\n## Note\n\nCurrently `AjaxDatatablesRails` only supports `ActiveRecord` as ORM for performing database queries.\n\nAdding support for `Sequel`, `Mongoid` and `MongoMapper` is (more or less) a planned feature for this gem.\n\nIf you'd be interested in contributing to speed development, please [open an issue](https://github.com/antillas21/ajax-datatables-rails/issues/new) and get in touch.\n\n\n## Quick start (in 5 steps)\n\nThe following examples assume that we are setting up `ajax-datatables-rails` for an index page of users from a `User` model,\nand that we are using Postgresql as our db, because you **should be using it**. (It also works with other DB, [see above](#change-the-db-adapter-for-a-datatable-class))\n\nThe goal is to render a users table and display : `id`, `first name`, `last name`, `email`, and `bio` for each user.\n\nSomething like this:\n\n|ID |First Name|Last Name|Email                 |Brief Bio|\n|---|----------|---------|----------------------|---------|\n| 1 |John      |Doe      |john.doe@example.net  |Is your default user everywhere|\n| 2 |Jane      |Doe      |jane.doe@example.net  |Is John's wife|\n| 3 |James     |Doe      |james.doe@example.net |Is John's brother and best friend|\n\nHere the steps we're going through :\n\n1. [Generate the datatable class](#1-generate-the-datatable-class)\n2. [Build the View](#2-build-the-view)\n3. [Customize the generated Datatables class](#3-customize-the-generated-datatables-class)\n4. [Setup the Controller action](#4-setup-the-controller-action)\n5. [Wire up the Javascript](#5-wire-up-the-javascript)\n\n### 1) Generate the datatable class\n\nRun the following command:\n\n```sh\n$ rails generate datatable User\n```\n\nThis will generate a file named `user_datatable.rb` in `app/datatables`.\nOpen the file and customize in the functions as directed by the comments.\n\nTake a look [here](#generator-syntax) for an explanation about the generator syntax.\n\n\n### 2) Build the View\n\nYou should always start by the single source of truth, which is your html view.\n\n* Set up an html `\u003ctable\u003e` with a `\u003cthead\u003e` and `\u003ctbody\u003e`\n* Add in your table headers if desired\n* Don't add any rows to the body of the table, DataTables does this automatically\n* Add a data attribute to the `\u003ctable\u003e` tag with the url of the JSON feed, in our case is the `users_path` as we're pointing to the `UsersController#index` action\n\n\n```html\n\u003ctable id=\"users-datatable\" data-source=\"\u003c%= users_path(format: :json) %\u003e\"\u003e\n  \u003cthead\u003e\n    \u003ctr\u003e\n      \u003cth\u003eID\u003c/th\u003e\n      \u003cth\u003eFirst Name\u003c/th\u003e\n      \u003cth\u003eLast Name\u003c/th\u003e\n      \u003cth\u003eEmail\u003c/th\u003e\n      \u003cth\u003eBrief Bio\u003c/th\u003e\n    \u003c/tr\u003e\n  \u003c/thead\u003e\n  \u003ctbody\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n```\n\n\n### 3) Customize the generated Datatables class\n\n#### a. Declare columns mapping\n\nFirst we need to declare in `view_columns` the list of the model(s) columns mapped to the data we need to present.\nIn this case: `id`, `first_name`, `last_name`, `email` and `bio`.\n\nThis gives us:\n\n```ruby\ndef view_columns\n  @view_columns ||= {\n    id:         { source: \"User.id\" },\n    first_name: { source: \"User.first_name\", cond: :like, searchable: true, orderable: true },\n    last_name:  { source: \"User.last_name\",  cond: :like, nulls_last: true },\n    email:      { source: \"User.email\" },\n    bio:        { source: \"User.bio\" },\n  }\nend\n```\n\n**Notes :** by default `orderable` and `searchable` are true and `cond` is `:like`.\n\n`cond` can be :\n\n* `:like`, `:start_with`, `:end_with`, `:string_eq`, `:string_in` for string or full text search\n* `:eq`, `:not_eq`, `:lt`, `:gt`, `:lteq`, `:gteq`, `:in` for numeric\n* `:date_range` for date range\n* `:null_value` for nil field\n* `Proc` for whatever (see [here](https://github.com/jbox-web/ajax-datatables-rails-sample-project/blob/master/app/datatables/city_datatable.rb) for real example)\n\nThe `nulls_last` param allows for nulls to be ordered last. You can configure it by column, like above, or by datatable class :\n\n```ruby\nclass MyDatatable \u003c AjaxDatatablesRails::ActiveRecord\n  self.nulls_last = true\n\n  # ... other methods (view_columns, data...)\nend\n```\n\nSee [here](#columns-syntax) to get more details about columns definitions and how to play with associated models.\n\nYou can customize or sanitize the search value passed to the DB by using the `:formatter` option with a lambda :\n\n```ruby\ndef view_columns\n  @view_columns ||= {\n    id:         { source: \"User.id\" },\n    first_name: { source: \"User.first_name\" },\n    last_name:  { source: \"User.last_name\" },\n    email:      { source: \"User.email\", formatter: -\u003e (o) { o.upcase } },\n    bio:        { source: \"User.bio\" },\n  }\nend\n```\n\nThe object passed to the lambda is the search value.\n\n#### b. Map data\n\nThen we need to map the records retrieved by the `get_raw_records` method to the real values we want to display :\n\n```ruby\ndef data\n  records.map do |record|\n    {\n      id:         record.id,\n      first_name: record.first_name,\n      last_name:  record.last_name,\n      email:      record.email,\n      bio:        record.bio,\n      DT_RowId:   record.id, # This will automagically set the id attribute on the corresponding \u003ctr\u003e in the datatable\n    }\n  end\nend\n```\n\n**Deprecated:** You can either use the v0.3 Array style for your columns :\n\nThis method builds a 2d array that is used by datatables to construct the html\ntable. Insert the values you want on each column.\n\n```ruby\ndef data\n  records.map do |record|\n    [\n      record.id,\n      record.first_name,\n      record.last_name,\n      record.email,\n      record.bio\n    ]\n  end\nend\n```\n\nThe drawback of this method is that you can't pass the `DT_RowId` so it's tricky to set the id attribute on the corresponding `\u003ctr\u003e` in the datatable (need to be done on JS side).\n\n[See here](#using-view-helpers) if you need to use view helpers like `link_to`, `mail_to`, etc...\n\n#### c. Get Raw Records\n\nThis is where your query goes.\n\n```ruby\ndef get_raw_records\n  User.all\nend\n```\n\nObviously, you can construct your query as required for the use case the datatable is used.\n\nExample:\n\n```ruby\ndef get_raw_records\n  User.active.with_recent_messages\nend\n```\n\nYou can put any logic in `get_raw_records` [based on any parameters you inject](#pass-options-to-the-datatable-class) in the `Datatable` object.\n\n**IMPORTANT :** Because the result of this method will be chained to `ActiveRecord` methods for sorting, filtering and pagination,\nmake sure to return an `ActiveRecord::Relation` object.\n\n#### d. Additional data\n\nYou can inject other key/value pairs in the rendered JSON by defining the `#additional_data` method :\n\n```ruby\ndef additional_data\n  {\n    foo: 'bar'\n  }\nend\n```\n\nVery useful with [datatables-factory](https://github.com/jbox-web/datatables-factory) (or [yadcf](https://github.com/vedmack/yadcf)) to provide values for dropdown filters.\n\n\n### 4) Setup the Controller action\n\nSet the controller to respond to JSON\n\n```ruby\ndef index\n  respond_to do |format|\n    format.html\n    format.json { render json: UserDatatable.new(params) }\n  end\nend\n```\n\nDon't forget to make sure the proper route has been added to `config/routes.rb`.\n\n[See here](#pass-options-to-the-datatable-class) if you need to inject params in the `UserDatatable`.\n\n**Note :** If you have more than **2** datatables in your application, don't forget to read [this](#use-http-post-method-medium).\n\n### 5) Wire up the Javascript\n\nFinally, the javascript to tie this all together. In the appropriate `coffee` file:\n\n```coffeescript\n# users.coffee\n\n$ -\u003e\n  $('#users-datatable').dataTable\n    processing: true\n    serverSide: true\n    ajax:\n      url: $('#users-datatable').data('source')\n    pagingType: 'full_numbers'\n    columns: [\n      {data: 'id'}\n      {data: 'first_name'}\n      {data: 'last_name'}\n      {data: 'email'}\n      {data: 'bio'}\n    ]\n    # pagingType is optional, if you want full pagination controls.\n    # Check dataTables documentation to learn more about\n    # available options.\n```\n\nor, if you're using plain javascript:\n\n```javascript\n// users.js\n\njQuery(document).ready(function() {\n  $('#users-datatable').dataTable({\n    \"processing\": true,\n    \"serverSide\": true,\n    \"ajax\": {\n      \"url\": $('#users-datatable').data('source')\n    },\n    \"pagingType\": \"full_numbers\",\n    \"columns\": [\n      {\"data\": \"id\"},\n      {\"data\": \"first_name\"},\n      {\"data\": \"last_name\"},\n      {\"data\": \"email\"},\n      {\"data\": \"bio\"}\n    ]\n    // pagingType is optional, if you want full pagination controls.\n    // Check dataTables documentation to learn more about\n    // available options.\n  });\n});\n```\n\n## Advanced usage\n\n### Using view helpers\n\nSometimes you'll need to use view helper methods like `link_to`, `mail_to`,\n`edit_user_path`, `check_box_tag` and so on in the returned JSON representation returned by the [`data`](#b-map-data) method.\n\nTo have these methods available to be used, this is the way to go:\n\n```ruby\nclass UserDatatable \u003c AjaxDatatablesRails::ActiveRecord\n  extend Forwardable\n\n  # either define them one-by-one\n  def_delegator :@view, :check_box_tag\n  def_delegator :@view, :link_to\n  def_delegator :@view, :mail_to\n  def_delegator :@view, :edit_user_path\n\n  # or define them in one pass\n  def_delegators :@view, :check_box_tag, :link_to, :mail_to, :edit_user_path\n\n  # ... other methods (view_columns, get_raw_records...)\n\n  def initialize(params, opts = {})\n    @view = opts[:view_context]\n    super\n  end\n\n  # now, you'll have these methods available to be used anywhere\n  def data\n    records.map do |record|\n      {\n        id:         check_box_tag('users[]', record.id),\n        first_name: link_to(record.first_name, edit_user_path(record)),\n        last_name:  record.last_name,\n        email:      mail_to(record.email),\n        bio:        record.bio\n        DT_RowId:   record.id,\n      }\n    end\n  end\nend\n\n# and in your controller:\ndef index\n  respond_to do |format|\n    format.html\n    format.json { render json: UserDatatable.new(params, view_context: view_context) }\n  end\nend\n```\n\n### Using view decorators\n\nIf you want to keep things tidy in the data mapping method, you could use\n[Draper](https://github.com/drapergem/draper) to define column mappings like below.\n\n**Note :** This is the recommanded way as you don't need to inject the `view_context` in the Datatable object to access helpers methods.\nIt also helps in separating view/presentation logic from filtering logic (the only one that really matters in a datatable class).\n\nExample :\n\n```ruby\nclass UserDatatable \u003c AjaxDatatablesRails::ActiveRecord\n  ...\n  def data\n    records.map do |record|\n      {\n        id:         record.decorate.check_box,\n        first_name: record.decorate.link_to,\n        last_name:  record.decorate.last_name\n        email:      record.decorate.email,\n        bio:        record.decorate.bio\n        DT_RowId:   record.id,\n      }\n    end\n  end\n  ...\nend\n\nclass UserDecorator \u003c ApplicationDecorator\n  delegate :last_name, :bio\n\n  def check_box\n    h.check_box_tag 'users[]', object.id\n  end\n\n  def link_to\n    h.link_to object.first_name, h.edit_user_path(object)\n  end\n\n  def email\n    h.mail_to object.email\n  end\n\n  # Just an example of a complex method you can add to you decorator\n  # To render it in a datatable just add a column 'dt_actions' in\n  # 'view_columns' and 'data' methods and call record.decorate.dt_actions\n  def dt_actions\n    links = []\n    links \u003c\u003c h.link_to 'Edit',   h.edit_user_path(object) if h.policy(object).update?\n    links \u003c\u003c h.link_to 'Delete', h.user_path(object), method: :delete, remote: true if h.policy(object).destroy?\n    h.safe_join(links, '')\n  end\nend\n```\n\n### Pass options to the datatable class\n\nAn `AjaxDatatablesRails::ActiveRecord` inherited class can accept an options hash at initialization. This provides room for flexibility when required.\n\nExample:\n\n```ruby\n# In the controller\ndef index\n  respond_to do |format|\n    format.html\n    format.json { render json: UserDatatable.new(params, user: current_user, from: 1.month.ago) }\n  end\nend\n\n# The datatable class\nclass UnrespondedMessagesDatatable \u003c AjaxDatatablesRails::ActiveRecord\n\n  # ... other methods (view_columns, data...)\n\n  def user\n    @user ||= options[:user]\n  end\n\n  def from\n    @from ||= options[:from].beginning_of_day\n  end\n\n  def to\n    @to ||= Date.today.end_of_day\n  end\n\n  # We can now customize the get_raw_records method\n  # with the options we've injected\n  def get_raw_records\n    user.messages.unresponded.where(received_at: from..to)\n  end\n\nend\n```\n\n### Change the DB adapter for a datatable class\n\nIf you have models from different databases you can set the `db_adapter` on the datatable class :\n\n```ruby\nclass MySharedModelDatatable \u003c AjaxDatatablesRails::ActiveRecord\n  self.db_adapter = :oracle_enhanced\n\n  # ... other methods (view_columns, data...)\n\n  def get_raw_records\n    AnimalsRecord.connected_to(role: :reading) do\n      Dog.all\n    end\n  end\nend\n```\n\n### Columns syntax\n\nYou can mix several model in the same datatable.\n\nSuppose we have the following models: `User`, `PurchaseOrder`,\n`Purchase::LineItem` and we need to have several columns from those models\navailable in our datatable to search and sort by.\n\n```ruby\n# we use the ModelName.column_name notation to declare our columns\n\ndef view_columns\n  @view_columns ||= {\n    first_name:       { source: 'User.first_name' },\n    last_name:        { source: 'User.last_name' },\n    order_number:     { source: 'PurchaseOrder.number' },\n    order_created_at: { source: 'PurchaseOrder.created_at' },\n    quantity:         { source: 'Purchase::LineItem.quantity' },\n    unit_price:       { source: 'Purchase::LineItem.unit_price' },\n    item_total:       { source: 'Purchase::LineItem.item_total }'\n  }\nend\n```\n\n### Associated and nested models\n\nThe previous example has only one single model. But what about if you have\nsome associated nested models and in a report you want to show fields from\nthese tables.\n\nTake an example that has an `Event, Course, CourseType, Allocation, Teacher,\nContact, Competency and CompetencyType` models. We want to have a datatables\nreport which has the following column:\n\n```ruby\n'course_types.name'\n'courses.name'\n'contacts.full_name'\n'competency_types.name'\n'events.title'\n'events.event_start'\n'events.event_end'\n'events.status'\n```\n\nWe want to sort and search on all columns of the list.\nThe related definition would be :\n\n```ruby\ndef view_columns\n  @view_columns ||= {\n    course_type:     { source: 'CourseType.name' },\n    course_name:     { source: 'Course.name' },\n    contact_name:    { source: 'Contact.full_name' },\n    competency_type: { source: 'CompetencyType.name' },\n    event_title:     { source: 'Event.title' },\n    event_start:     { source: 'Event.event_start' },\n    event_end:       { source: 'Event.event_end' },\n    event_status:    { source: 'Event.status' },\n  }\nend\n\ndef get_raw_records\n  Event.joins(\n    { course: :course_type },\n    { allocations: {\n      teacher: [:contact, { competencies: :competency_type }]\n    }\n  }).distinct\nend\n```\n\n**Some comments for the above code :**\n\n1. In the `get_raw_records` method we have quite a complex query having one to\nmany and many to many associations using the joins ActiveRecord method.\nThe joins will generate INNER JOIN relations in the SQL query. In this case,\nwe do not include all event in the report if we have events which is not\nassociated with any model record from the relation.\n\n2. To have all event records in the list we should use the `.includes` method,\nwhich generate LEFT OUTER JOIN relation of the SQL query.\n\n**IMPORTANT :**\n\nMake sure to append `.references(:related_model)` with any\nassociated model. That forces the eager loading of all the associated models\nby one SQL query, and the search condition for any column works fine.\nOtherwise the `:recordsFiltered =\u003e filter_records(get_raw_records).count(:all)`\nwill generate 2 SQL queries (one for the Event model, and then another for the\nassociated tables). The `:recordsFiltered =\u003e filter_records(get_raw_records).count(:all)`\nwill use only the first one to return from the ActiveRecord::Relation object\nin `get_raw_records` and you will get an error message of **Unknown column\n'yourtable.yourfield' in 'where clause'** in case the search field value\nis not empty.\n\nSo the query using the `.includes()` method is:\n\n```ruby\ndef get_raw_records\n  Event.includes(\n    { course: :course_type },\n    { allocations: {\n      teacher: [:contact, { competencies: :competency_type }]\n    }\n  }).references(:course).distinct\nend\n```\n\n### Default scope\n\nSee [DefaultScope is evil](https://rails-bestpractices.com/posts/2013/06/15/default_scope-is-evil/) and [#223](https://github.com/jbox-web/ajax-datatables-rails/issues/223) and [#233](https://github.com/jbox-web/ajax-datatables-rails/issues/233).\n\n### DateRange search\n\nThis feature works with [datatables-factory](https://github.com/jbox-web/datatables-factory) (or [yadcf](https://github.com/vedmack/yadcf)).\n\nTo enable the date range search, for example `created_at` :\n\n* add a `created_at` `\u003cth\u003e` in your html\n* declare your column in `view_columns` : `created_at: { source: 'Post.created_at', cond: :date_range, delimiter: '-yadcf_delim-' }`\n* add it in `data` : `created_at: record.decorate.created_at`\n* setup yadcf to make `created_at` search field a range\n\n### Generator Syntax\n\nAlso, a class that inherits from `AjaxDatatablesRails::ActiveRecord` is not tied to an\nexisting model, module, constant or any type of class in your Rails app.\nYou can pass a name to your datatable class like this:\n\n\n```sh\n$ rails generate datatable users\n# returns a users_datatable.rb file with a UsersDatatable class\n\n$ rails generate datatable contact_messages\n# returns a contact_messages_datatable.rb file with a ContactMessagesDatatable class\n\n$ rails generate datatable UnrespondedMessages\n# returns an unresponded_messages_datatable.rb file with an UnrespondedMessagesDatatable class\n```\n\nIn the end, it's up to the developer which model(s), scope(s), relationship(s)\n(or else) to employ inside the datatable class to retrieve records from the\ndatabase.\n\n## Tests\n\nDatatables can be tested with Capybara provided you don't use Webrick during integration tests.\n\nLong story short and as a rule of thumb : use the same webserver everywhere (dev, prod, staging, test, etc...).\n\nIf you use Puma (the Rails default webserver), use Puma everywhere, even in CI/test environment. The same goes for Thin.\n\nYou will avoid the usual story : it works in dev but not in test environment...\n\nIf you want to test datatables with a lot of data you might need this kind of tricks : https://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara. (thanks CharlieIGG)\n\n## ProTips™\n\n### Create a master parent class (Easy)\n\nIn the same spirit of Rails `ApplicationController` and `ApplicationRecord`, you can create an `ApplicationDatatable` class (in `app/datatables/application_datatable.rb`)\nthat will be inherited from other classes :\n\n```ruby\nclass ApplicationDatatable \u003c AjaxDatatablesRails::ActiveRecord\n  # puts commonly used methods here\nend\n\nclass PostDatatable \u003c ApplicationDatatable\nend\n```\n\nThis way it will be easier to DRY you datatables.\n\n### Speedup JSON rendering (Easy)\n\nInstall [yajl-ruby](https://github.com/brianmario/yajl-ruby), basically :\n\n```ruby\ngem 'yajl-ruby', require: 'yajl'\n```\n\nthen\n\n```sh\n$ bundle install\n```\n\nThat's all :) ([Automatically prefer Yajl or JSON backend over Yaml, if available](https://github.com/rails/rails/commit/63bb955a99eb46e257655c93dd64e86ebbf05651))\n\n### Use HTTP `POST` method (Medium)\n\nUse HTTP `POST` method to avoid `414 Request-URI Too Large` error. See : [#278](https://github.com/jbox-web/ajax-datatables-rails/issues/278) and [#308](https://github.com/jbox-web/ajax-datatables-rails/issues/308#issuecomment-424897335).\n\nYou can easily define a route concern in `config/routes.rb` and reuse it when you need it :\n\n```ruby\nRails.application.routes.draw do\n  concern :with_datatable do\n    post 'datatable', on: :collection\n  end\n\n  resources :posts, concerns: [:with_datatable]\n  resources :users, concerns: [:with_datatable]\nend\n```\n\nthen in your controllers :\n\n```ruby\n# PostsController\n  def index\n  end\n\n  def datatable\n    render json: PostDatatable.new(params)\n  end\n\n# UsersController\n  def index\n  end\n\n  def datatable\n    render json: UserDatatable.new(params)\n  end\n```\n\nthen in your views :\n\n```html\n# posts/index.html.erb\n\u003ctable id=\"posts-datatable\" data-source=\"\u003c%= datatable_posts_path(format: :json) %\u003e\"\u003e\n\n# users/index.html.erb\n\u003ctable id=\"users-datatable\" data-source=\"\u003c%= datatable_users_path(format: :json) %\u003e\"\u003e\n```\n\nthen in your Coffee/JS :\n\n```coffee\n# send params in form data\n$ -\u003e\n  $('#posts-datatable').dataTable\n    ajax:\n      url: $('#posts-datatable').data('source')\n      type: 'POST'\n    # ...others options, see [here](#5-wire-up-the-javascript)\n\n# send params as json data\n$ -\u003e\n  $('#users-datatable').dataTable\n    ajax:\n      url: $('#users-datatable').data('source')\n      contentType: 'application/json'\n      type: 'POST'\n      data: (d) -\u003e\n        JSON.stringify d\n    # ...others options, see [here](#5-wire-up-the-javascript)\n```\n\n### Create indices for Postgresql (Expert)\n\nIn order to speed up the `ILIKE` queries that are executed when using the default configuration, you might want to consider adding some indices.\nFor postgresql, you are advised to use the [gin/gist index type](http://www.postgresql.org/docs/current/interactive/pgtrgm.html).\nThis makes it necessary to enable the postgrsql extension `pg_trgm`. Double check that you have this extension installed before trying to enable it.\nA migration for enabling the extension and creating the indices could look like this:\n\n```ruby\ndef change\n  enable_extension :pg_trgm\n  TEXT_SEARCH_ATTRIBUTES = ['your', 'attributes']\n  TABLE = 'your_table'\n\n  TEXT_SEARCH_ATTRIBUTES.each do |attr|\n    reversible do |dir|\n      dir.up do\n        execute \"CREATE INDEX #{TABLE}_#{attr}_gin ON #{TABLE} USING gin(#{attr} gin_trgm_ops)\"\n      end\n\n      dir.down do\n        remove_index TABLE.to_sym, name: \"#{TABLE}_#{attr}_gin\"\n      end\n    end\n  end\nend\n```\n\n## Tutorial\n\nFiltering by JSONB column values : [#277](https://github.com/jbox-web/ajax-datatables-rails/issues/277#issuecomment-366526373)\n\nUse [has_scope](https://github.com/plataformatec/has_scope) gem with `ajax-datatables-rails` : [#280](https://github.com/jbox-web/ajax-datatables-rails/issues/280)\n\nUse [Datatable orthogonal data](https://datatables.net/manual/data/orthogonal-data) : see [#269](https://github.com/jbox-web/ajax-datatables-rails/issues/269#issuecomment-387940478)\n\n## Contributing\n\n1. Fork it\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Commit your changes (`git commit -am 'Added some feature'`)\n4. Push to the branch (`git push origin my-new-feature`)\n5. Create new Pull Request\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjbox-web%2Fajax-datatables-rails","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjbox-web%2Fajax-datatables-rails","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjbox-web%2Fajax-datatables-rails/lists"}