From caa63f9c1c8998c0b0b6ce6b889f7ed7f71b9f73 Mon Sep 17 00:00:00 2001 From: Nishanth Vijayan Date: Mon, 1 Aug 2016 02:32:48 +0530 Subject: [PATCH 1/3] Implement server-side rendering of datatables in users#index --- app/assets/javascripts/osem-datatables.js | 9 +++- app/controllers/admin/users_controller.rb | 5 ++- app/datatables/users_datatable.rb | 53 +++++++++++++++++++++++ app/views/admin/users/index.html.haml | 30 +------------ 4 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 app/datatables/users_datatable.rb diff --git a/app/assets/javascripts/osem-datatables.js b/app/assets/javascripts/osem-datatables.js index f950159e..b6453604 100644 --- a/app/assets/javascripts/osem-datatables.js +++ b/app/assets/javascripts/osem-datatables.js @@ -12,7 +12,14 @@ $(function () { pagingType: 'full_numbers', order: [[ 0, 'desc' ]] }); + + $('#userstable').DataTable({ + pagingType: 'full_numbers', + processing: true, + serverSide: true, + sAjaxSource: $('#userstable').data('source'), + aoColumns: [ null, { "bSortable": false }, null, null, { "bSortable": false }, { "bSortable": false }, { "bSortable": false }, { "bSortable": false }] + }); }); }); - diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index dbd54ffd..139dfb67 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -7,7 +7,10 @@ module Admin end def index - @users = User.all + respond_to do |format| + format.html + format.json { render json: UsersDatatable.new(view_context) } + end end def show diff --git a/app/datatables/users_datatable.rb b/app/datatables/users_datatable.rb new file mode 100644 index 00000000..7f895b50 --- /dev/null +++ b/app/datatables/users_datatable.rb @@ -0,0 +1,53 @@ +class UsersDatatable + delegate :params, :link_to, :current_ability, :show_roles, to: :@view + + def initialize(view) + @view = view + end + + def as_json(_options = {}) + { + sEcho: params[:sEcho].to_i, + iTotalRecords: User.count, + iTotalDisplayRecords: users.count, + aaData: data + } + end + + private + + def data + paginate(users).map do |user| + [ + user.id, + (user.confirmed? ? 'confirmed' : 'unconfirmed'), + user.email, + user.name, + user.registrations.where(attended: true).count, + (user.roles.empty? ? 'None' : "#{show_roles(user.get_roles.first(2))} #{'...' if user.get_roles.count > 2}"), + (link_to('View', Rails.application.routes.url_helpers.admin_user_path(user), class: 'btn btn-success') if current_ability.can?(:show, user)), + (link_to('Edit', Rails.application.routes.url_helpers.edit_admin_user_path(user), class: 'btn btn-primary') if current_ability.can?(:update, user)) + ] + end + end + + def users + @users ||= fetch_users + end + + def fetch_users + sort_direction = params[:sSortDir_0] == 'desc' ? 'desc' : 'asc' + sort_column = %w(id state email name)[params[:iSortCol_0].to_i] + users = User.order("#{sort_column} #{sort_direction}") + if params[:sSearch].present? + users = users.where('name like :search or email like :search', search: "%#{params[:sSearch]}%") + end + users + end + + def paginate(users) + per_page = params[:iDisplayLength].to_i > 0 ? params[:iDisplayLength].to_i : 10 + page = params[:iDisplayStart].to_i / per_page + 1 + users.offset((page - 1) * per_page).limit(per_page) + end +end diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index c3d7b672..ffea91c2 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -7,7 +7,7 @@ = "(#{@users.length})" .row .col-md-12.table-responsive - %table.table.table-striped.table-bordered.table-hover.datatable + %table.table.table-striped.table-bordered.table-hover#userstable{data: {source: admin_users_path(format: :json)}} %thead %th ID %th State @@ -18,31 +18,3 @@ %th View %th Edit %tbody - - @users.each do |user| - %tr - %td - = user.id - %td - - if user.confirmed? - confirmed - - else - unconfirmed - %td - = user.email - %td - = user.name - %td - = user.registrations.where(attended: true).count - %td - - unless user.get_roles.blank? - = show_roles(user.get_roles.first(2)) - - if user.get_roles.count > 2 - = '...' - - else - None - %td - - if can? :show, user - = link_to 'View', admin_user_path(user), class: 'btn btn-success' - %td - - if can? :update, user - = link_to 'Edit', edit_admin_user_path(user), class: 'btn btn-primary' From 6cb6ddf78db00f9617cf153106193129a56bc4a2 Mon Sep 17 00:00:00 2001 From: Nishanth Vijayan Date: Tue, 9 Aug 2016 21:01:14 +0530 Subject: [PATCH 2/3] Generalized datatable class --- app/controllers/admin/users_controller.rb | 3 +- app/datatables/datatable.rb | 48 ++++++++++++++++++++ app/datatables/users_datatable.rb | 53 ----------------------- app/helpers/application_helper.rb | 13 ++++++ 4 files changed, 63 insertions(+), 54 deletions(-) create mode 100644 app/datatables/datatable.rb delete mode 100644 app/datatables/users_datatable.rb diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 139dfb67..7abdcfd0 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -7,9 +7,10 @@ module Admin end def index + users_datatable = Datatable.new(view_context, User.where(nil), %w(name email), %w(id state email name)) respond_to do |format| format.html - format.json { render json: UsersDatatable.new(view_context) } + format.json { render json: users_datatable.to_json(data: users_datatable.paginated_records.map {|user| users_datatable_data(user)}) } end end diff --git a/app/datatables/datatable.rb b/app/datatables/datatable.rb new file mode 100644 index 00000000..6f5d4340 --- /dev/null +++ b/app/datatables/datatable.rb @@ -0,0 +1,48 @@ +class Datatable + delegate :params, to: :@view + + def initialize(view, collection, search_columns, sort_columns) + @view = view + @collection = collection + @search_columns = search_columns + @sort_columns = sort_columns + end + + def as_json(options={}) + { + sEcho: params[:sEcho].to_i, + iTotalRecords: @collection.count, + iTotalDisplayRecords: records.count, + aaData: options[:data] + } + end + + def paginated_records + paginate(records) + end + + private + + def records + @records ||= fetch_records + end + + def fetch_records + sort_direction = params[:sSortDir_0] == 'desc' ? 'desc' : 'asc' + sort_column = @sort_columns[params[:iSortCol_0].to_i] + records = @collection.order("#{sort_column} #{sort_direction}") + if params[:sSearch].present? && @search_columns.present? + search_query = '' + @search_columns.each { |column| search_query += "#{column} like :search or " } + search_query = search_query.chomp(' or ') + records = records.where(search_query, search: "%#{params[:sSearch]}%") + end + records + end + + def paginate(records) + per_page = params[:iDisplayLength].to_i > 0 ? params[:iDisplayLength].to_i : 10 + page = params[:iDisplayStart].to_i / per_page + 1 + records.offset((page - 1) * per_page).limit(per_page) + end +end diff --git a/app/datatables/users_datatable.rb b/app/datatables/users_datatable.rb deleted file mode 100644 index 7f895b50..00000000 --- a/app/datatables/users_datatable.rb +++ /dev/null @@ -1,53 +0,0 @@ -class UsersDatatable - delegate :params, :link_to, :current_ability, :show_roles, to: :@view - - def initialize(view) - @view = view - end - - def as_json(_options = {}) - { - sEcho: params[:sEcho].to_i, - iTotalRecords: User.count, - iTotalDisplayRecords: users.count, - aaData: data - } - end - - private - - def data - paginate(users).map do |user| - [ - user.id, - (user.confirmed? ? 'confirmed' : 'unconfirmed'), - user.email, - user.name, - user.registrations.where(attended: true).count, - (user.roles.empty? ? 'None' : "#{show_roles(user.get_roles.first(2))} #{'...' if user.get_roles.count > 2}"), - (link_to('View', Rails.application.routes.url_helpers.admin_user_path(user), class: 'btn btn-success') if current_ability.can?(:show, user)), - (link_to('Edit', Rails.application.routes.url_helpers.edit_admin_user_path(user), class: 'btn btn-primary') if current_ability.can?(:update, user)) - ] - end - end - - def users - @users ||= fetch_users - end - - def fetch_users - sort_direction = params[:sSortDir_0] == 'desc' ? 'desc' : 'asc' - sort_column = %w(id state email name)[params[:iSortCol_0].to_i] - users = User.order("#{sort_column} #{sort_direction}") - if params[:sSearch].present? - users = users.where('name like :search or email like :search', search: "%#{params[:sSearch]}%") - end - users - end - - def paginate(users) - per_page = params[:iDisplayLength].to_i > 0 ? params[:iDisplayLength].to_i : 10 - page = params[:iDisplayStart].to_i / per_page + 1 - users.offset((page - 1) * per_page).limit(per_page) - end -end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 09f69484..24730355 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -491,4 +491,17 @@ module ApplicationHelper end end end + + def users_datatable_data(user) + [ + user.id, + (user.confirmed? ? 'confirmed' : 'unconfirmed'), + user.email, + user.name, + user.registrations.where(attended: true).count, + (user.roles.empty? ? 'None' : "#{show_roles(user.get_roles.first(2))} #{'...' if user.get_roles.count > 2}"), + (view_context.link_to('View', admin_user_path(user), class: 'btn btn-success') if current_ability.can?(:show, user)), + (view_context.link_to('Edit', edit_admin_user_path(user), class: 'btn btn-primary') if current_ability.can?(:update, user)) + ] + end end From 7d3a6ab05c6fe0f7c848fef9f76df93fc696c61c Mon Sep 17 00:00:00 2001 From: Nishanth Vijayan Date: Tue, 9 Aug 2016 23:00:11 +0530 Subject: [PATCH 3/3] Refactor datatable class to a controller concern --- app/controllers/admin/users_controller.rb | 7 +++-- .../datatable_serverside_processing.rb} | 26 ++++++++----------- 2 files changed, 16 insertions(+), 17 deletions(-) rename app/{datatables/datatable.rb => controllers/concerns/datatable_serverside_processing.rb} (71%) diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 7abdcfd0..5d01278b 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -1,16 +1,19 @@ module Admin class UsersController < Admin::BaseController load_and_authorize_resource + include DatatableServersideProcessing def new @user = User.new end def index - users_datatable = Datatable.new(view_context, User.where(nil), %w(name email), %w(id state email name)) + @users = filtered_records(User.where(nil), %w(name email), %w(id state email name)) respond_to do |format| format.html - format.json { render json: users_datatable.to_json(data: users_datatable.paginated_records.map {|user| users_datatable_data(user)}) } + format.json do + render json: datatable_response(@users.map {|user| users_datatable_data(user)}) + end end end diff --git a/app/datatables/datatable.rb b/app/controllers/concerns/datatable_serverside_processing.rb similarity index 71% rename from app/datatables/datatable.rb rename to app/controllers/concerns/datatable_serverside_processing.rb index 6f5d4340..42f7b3cf 100644 --- a/app/datatables/datatable.rb +++ b/app/controllers/concerns/datatable_serverside_processing.rb @@ -1,23 +1,19 @@ -class Datatable - delegate :params, to: :@view +module DatatableServersideProcessing + extend ActiveSupport::Concern - def initialize(view, collection, search_columns, sort_columns) - @view = view - @collection = collection - @search_columns = search_columns - @sort_columns = sort_columns - end - - def as_json(options={}) + def datatable_response(data) { sEcho: params[:sEcho].to_i, iTotalRecords: @collection.count, iTotalDisplayRecords: records.count, - aaData: options[:data] + aaData: data } end - def paginated_records + def filtered_records(collection, search_columns, sort_columns) + @collection = collection + @search_columns = search_columns + @sort_columns = sort_columns paginate(records) end @@ -31,12 +27,12 @@ class Datatable sort_direction = params[:sSortDir_0] == 'desc' ? 'desc' : 'asc' sort_column = @sort_columns[params[:iSortCol_0].to_i] records = @collection.order("#{sort_column} #{sort_direction}") + if params[:sSearch].present? && @search_columns.present? - search_query = '' - @search_columns.each { |column| search_query += "#{column} like :search or " } - search_query = search_query.chomp(' or ') + search_query = @search_columns.map{ |column| "#{column} like :search" }.join(' or ') records = records.where(search_query, search: "%#{params[:sSearch]}%") end + records end