Skip to content

Commit

Permalink
[DRAFT] drafts changes for version 0.3.0
Browse files Browse the repository at this point in the history
* found a better way to declare models and columns inside the searchable
  and sortable columns methods
* for the time being, the old way of declaring such columns will be
  supported, but it will display a deprecation warning.
  • Loading branch information
antillas21 committed Dec 3, 2014
1 parent 1895169 commit 70d4b27
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 107 deletions.
154 changes: 94 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,12 @@ Take a look [here](#generator-syntax) for an explanation about the generator syn
# include AjaxDatatablesRails::Extensions::SimplePaginator

def sortable_columns
# list columns inside the Array in string dot notation.
# Example: 'users.email'
# Declare strings in this format: ModelName.column_name
@sortable_columns ||= []
end

def searchable_columns
# list columns inside the Array in string dot notation.
# Example: 'users.email'
# Declare strings in this format: ModelName.column_name
@searchable_columns ||= []
end
```
Expand All @@ -90,23 +88,28 @@ the gems bundled in your project. For example, if your models are using `Kaminar

* For `sortable_columns`, assign an array of the database columns that correspond to the columns in our view table. For example `[users.f_name, users.l_name, users.bio]`. This array is used for sorting by various columns.

* For `searchable_columns`, assign an array of the database columns that you want searchable by datatables. For example `[users.f_name, users.l_name]`
* For `searchable_columns`, assign an array of the database columns that you want searchable by datatables. Suppose we need to sort and search users `:first_name`, `last_name` and `bio`.

This gives us:

```ruby
include AjaxDatatablesRails::Extensions::Kaminari

def sortable_columns
@sortable_columns ||= ['users.f_name', 'users.l_name', 'users.bio']
@sortable_columns ||= %w(User.first_name User.last_name User.bio)
# this is equal to:
# @sortable_columns ||= ['User.first_name', 'User.last_name', 'User.bio']
end

def searchable_columns
@searchable_columns ||= ['users.f_name', 'users.l_name']
@searchable_columns ||= %w(User.first_name User.last_name User.bio)
# this is equal to:
# @searchable_columns ||= ['User.first_name', 'User.last_name', 'User.bio']
end
```

[See here](#searching-on-non-text-based-columns) for notes regarding database config (if using something different from `postgre`).
* [See here](#searching-on-non-text-based-columns) for notes about the `searchable_columns` settings (if using something different from `postgre`).
* [Read these notes](#searchable-and-sortable-columns-syntax) about considerations for the `searchable_columns` and `sortable_columns` methods.

### Map data
```ruby
Expand All @@ -126,8 +129,8 @@ This method builds a 2d array that is used by datatables to construct the html t
def data
records.map do |record|
[
record.f_name,
record.l_name,
record.first_name,
record.last_name,
record.bio
]
end
Expand Down Expand Up @@ -174,27 +177,27 @@ We want to sort and search on all columns of the list. The related definition wo

def sortable_columns
@sortable_columns ||= [
'coursetypes.name',
'courses.name',
'events.title',
'events.event_start',
'events.event_end',
'contacts.last_name',
'competency_types.name',
'events.status'
'Coursetype.name',
'Course.name',
'Event.title',
'Event.event_start',
'Event.event_end',
'Contact.last_name',
'CompetencyType.name',
'Event.status'
]
end

def searchable_columns
@searchable_columns ||= [
'coursetypes.name',
'courses.name',
'events.title',
'events.event_start',
'events.event_end',
'contacts.last_name',
'competency_types.name',
'events.status'
'Coursetype.name',
'Course.name',
'Event.title',
'Event.event_start',
'Event.event_end',
'Contact.last_name',
'CompetencyType.name',
'Event.status'
]
end

Expand Down Expand Up @@ -230,38 +233,6 @@ So the query using the `.includes()` method is:
end
```

#### NOTE for model class that different from table name
currently model class name detected by singularize the table name
so if your table name is different, or you have namespaced model, you should set the model name like this

create the `setup` method (`setup` method will be executed when AjaxDatatablesRails class initialized)

then create `set_model_class` block inside `setup` method

```ruby
def setup
set_model_class do |klass|
klass.users = Employee
end
end
```
now you can use `users.name` at `sortable_columns` and `searchable_columns` methods
```ruby
@sortable_columns ||= [ 'users.name']
```

##### TIPS, you can use above step to abbreviate long namespaced model
```ruby
def setup
set_model_class do |klass|
klass.requests = Statistics::Request
klass.sessions = Statistics::Session
end
end
def searchable_columns
@sortable_columns ||= [ 'requests.foo', 'sessions.bar']
end
```

### Controller
Set up the controller to respond to JSON
Expand All @@ -277,15 +248,17 @@ end

Don't forget to make sure the proper route has been added to `config/routes.rb`.


### View

* Set up an html `<table>` with a `<thead>` and `<tbody>`
* Add in your table headers if desired
* Don't add any rows to the body of the table, datatables does this automatically
* Add a data attribute to the `<table>` tag with the url of the JSON feed

The resulting view may look like this:

```erb
```html
<table id="users-table", data-source="<%= users_path(format: :json) %>">
<thead>
<tr>
Expand All @@ -300,9 +273,11 @@ The resulting view may look like this:
```

### Javascript
Finally, the javascript to tie this all together. In the appropriate `js.coffee` file:
Finally, the javascript to tie this all together. In the appropriate `coffee` file:

```coffeescript
# users.coffee

$ ->
$('#users-table').dataTable
processing: true
Expand Down Expand Up @@ -333,6 +308,65 @@ jQuery(document).ready(function() {

### Additional Notes

#### Searchable and Sortable columns syntax

Starting on version `0.3.0`, we are implementing a pseudo code way of declaring the array of both `searchable_columns` and `sortable_columns` method.

Example. Suppose we have the following models: `User`, `PurchaseOrder`, `Purchase::LineItem` and we need to have several columns from those models available in our datatable to search and sort by.

```ruby
# we use the ModelName.column_name notation to declare our columns

def searchable_columns
@searchable_columns ||= [
'User.first_name',
'User.last_name',
'PurchaseOrder.number',
'PurchaseOrder.created_at',
'Purchase::LineItem.quantity',
'Purchase::LineItem.unit_price',
'Purchase::LineItem.item_total'
]
end

def sortable_columns
@sortable_columns ||= [
'User.first_name',
'User.last_name',
'PurchaseOrder.number',
'PurchaseOrder.created_at'
]
end
```

##### What if the datatable itself is namespaced?
Example: what if the datatable is namespaced into an `Admin` module?

```ruby
module Admin
class PurchasesDatatable < AjaxDatatablesRails::Base
end
end
```

Taking the same models and columns, we would define it like this:

```ruby
def searchable_columns
@searchable_columns ||= [
'::User.first_name',
'::User.last_name',
'::PurchaseOrder.number',
'::PurchaseOrder.created_at',
'::Purchase::LineItem.quantity',
'::Purchase::LineItem.unit_price',
'::Purchase::LineItem.item_total'
]
end
```

Pretty much like you would do it, if you were inside a namespaced controller.

#### Searching on non text-based columns

It always comes the time when you need to add a non-string/non-text based column to the `@searchable_columns` array, so you can perform searches against these column types (example: numeric, date, time).
Expand Down
63 changes: 41 additions & 22 deletions lib/ajax-datatables-rails/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,6 @@ class MethodNotImplementedError < StandardError; end
def initialize(view, options = {})
@view = view
@options = options
setup
end

def set_model_class
@models ||= AjaxDatatablesRails::Models.new
yield @models
end

def setup
end

def models
@models ||= AjaxDatatablesRails::Models.new
end

def config
Expand Down Expand Up @@ -59,6 +46,16 @@ def as_json(options = {})
}
end

def self.deprecated(message, caller = Kernel.caller[1])
warning = caller + ": " + message

if(respond_to?(:logger) && logger.present?)
logger.warn(warning)
else
warn(warning)
end
end

private

def records
Expand Down Expand Up @@ -116,12 +113,26 @@ def build_conditions_for(query)
end

def search_condition(column, value)
if column[0] == column.downcase[0]
::AjaxDatatablesRails::Base.deprecated '[DEPRECATED] Using table_name.column_name notation is deprecated. Please refer to: https://github.com/antillas21/ajax-datatables-rails#searchable-and-sortable-columns-syntax'
return deprecated_search_condition(column, value)
else
return new_search_condition(column, value)
end
end

def new_search_condition(column, value)
model, column = column.split('.')
model = model.constantize
casted_column = ::Arel::Nodes::NamedFunction.new('CAST', [model.arel_table[column.to_sym].as(typecast)])
casted_column.matches("%#{value}%")
end

def deprecated_search_condition(column, value)
model, column = column.split('.')
model_class = models[model]
model_class = model.singularize.titleize.gsub( / /, '' ).safe_constantize if model_class.nil?
raise("Model with class name #{model} not found") if model_class.nil?
model = model.singularize.titleize.gsub( / /, '' ).constantize

casted_column = ::Arel::Nodes::NamedFunction.new('CAST', [model_class.arel_table[column.to_sym].as(typecast)])
casted_column = ::Arel::Nodes::NamedFunction.new('CAST', [model.arel_table[column.to_sym].as(typecast)])
casted_column.matches("%#{value}%")
end

Expand Down Expand Up @@ -154,11 +165,19 @@ def per_page
end

def sort_column(item)
column = sortable_columns[item[:column].to_i]
return nil if column.nil?
model, col = column.split(".")
return [models[model].table_name.to_s, col].join(".") unless models[model].nil?
column
new_sort_column(item)
rescue
::AjaxDatatablesRails::Base.deprecated '[DEPRECATED] Using table_name.column_name notation is deprecated. Please refer to: https://github.com/antillas21/ajax-datatables-rails#searchable-and-sortable-columns-syntax'
deprecated_sort_column(item)
end

def deprecated_sort_column(item)
sortable_columns[item['column'].to_i]
end

def new_sort_column(item)
model, column = sortable_columns[item[:column].to_i].split('.')
col = [model.constantize.table_name, column].join('.')
end

def sort_direction(item)
Expand Down
2 changes: 1 addition & 1 deletion lib/ajax-datatables-rails/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module AjaxDatatablesRails
VERSION = '0.2.1'
VERSION = '0.3.0'
end
6 changes: 2 additions & 4 deletions lib/generators/rails/templates/datatable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@ class <%= @datatable_name %>Datatable < AjaxDatatablesRails::Base
# include AjaxDatatablesRails::Extensions::SimplePaginator

def sortable_columns
# list columns inside the Array in string dot notation.
# Example: 'users.email'
# Declare strings in this format: ModelName.column_name
@sortable_columns ||= []
end

def searchable_columns
# list columns inside the Array in string dot notation.
# Example: 'users.email'
# Declare strings in this format: ModelName.column_name
@searchable_columns ||= []
end

Expand Down
Loading

0 comments on commit 70d4b27

Please sign in to comment.