RichTableComponent

TODO: Write a gem description

Installation

Add this line to your application's Gemfile:

gem 'rich_table_component'

And then execute:

$ bundle

Or install it yourself as:

$ gem install rich_table_component

Or put in your gemfile gem 'rich_table_component'

Usage

CONTROLLER

rich_table_component(relation = {}, _sort_column = {}, _sort_direction = nil, pagination = true)

relation (required)

value: ActiveRecord::Relation
description:
    ActiveRecord::Relation bukan array. 
    Post, Post.where, User.posts adalah ActiveRecord::Relation
    Post.all adalah Array, bukan ActiveRecord::Relation 

sort_column (optional)

value: string
default: `created_at`
description:
    default kolom sorting yang diinginkan saat pertama kali ditampilkan

sort_direction (optional)

value: string
default: 'DESC'
description:
    mode urutan pada sorting dari kolom default/sort_column

pagination (optional)

value: boolean
default: true
description:
  Menyertakan fitur pagination jika true

contoh penggunaan pada controller:

@posts = rich_table_component Post
@posts = rich_table_component Post, sort_column: 'title', sort_direction: 'DESC'
@posts = rich_table_component Post, sort_column: 'title', sort_direction: 'DESC', pagination: false
@posts = rich_table_component Post, pagination: false
@posts = rich_table_component @q.result
@posts = rich_table_component @q.result, sort_column: 'title', sort_direction: 'DESC'
@posts = rich_table_component @q.result, sort_column: 'title', sort_direction: 'DESC', pagination: false
@posts = rich_table_component @q.result, pagination: false
@posts = rich_table_component @user.posts

instance name must plural e.g. @posts not @post

@posts = rich_table_component Post # right
@post = rich_table_component Post # WRONG

VIEW

= render 'shared/rtc/component' 

Merender file shared/rtc/_component.html.haml

PARAMETER:

rtc_controller_name

value: string
default: controller_name atau string dari controller yang menghandle request
description:
    Menentukan instance ActiveRecord::Relation yang ingin ditampilkan. Jika ingin menampilkan koleksi post melalui `PostsController#index`, maka default valuenya adalah 'posts'. Jika request bukan `controller#index` maka rtc_controller_name perlu dituliskan. Misalnya ingin menampilkan koleksi post pada halaman user pengupload atau `UsersController#show`, maka pada method `#show` perlu didefinisikan instance `@posts` dan parameter rtc_controller_name perlu dituliskan pada `render 'shared/rtc/component'` dengan value 'posts'.

rtc_partial

value: string
default: rtc_controller_name.singularize (jika default, merender file partial pada directory yang memanggil)
description:
    Partial per satu record atau per baris

rtc_title

value: boolean, Hash{ title: 'Judul', wrapper: 'h1'/'h2'/'h3'/'h4' }, or string
default: true
description: 
    Judul dari RTC

rtc_header

value: boolean
default: true
description:
    Menampilkan kotak header tabel jika true, dan tidak ditampilkan jika false

rtc_column_header

value: boolean
default: true
description:
    Menampilkan kotak header kolom header jika true, dan tidak ditampilkan jika false

rtc_footer

value: boolean
default: true
description:
    Menampilkan kotak footer tabel jika true, dan tidak ditampilkan jika false

headers (required)

value: Array of Object
description:
    Mendefinisikan atribut/kolom yang akan ditampilkan sebagai kolom header, berupa atribut pada model atau asosiasi model
example: 
  [:nip, :name, 'department', :nidn, :certification_number, 'user.email']

columns_width

value: Array of Integer
default: [] / empty array
description:
    Mengatur ukuran tiap kolom pada tabel. Nilai array merupakan rasio ukuran, misal: [1, 2, 2] berarti [20%, 40%, 40%]

search_constraint

value: symbol
default: nil
description:
    Mendefinisikan pencarian yang disediakan untuk single search pada kanan atas. Menggunakan syntax ransack

example:

:title_or_body_or_author_name_or_author_address_street_cont

advanced_search_attributes

value: Array of Object. Object can be string or symbol or hash {input: ..., params: simple_form input params}
default: nil
description:
    Menampilkan element advanced search pada rtc

example:

advanced_search_attributes: [ :nidn, 
                              :name,
                              :nip,
                              :ktp_number,
                              {input: 'department_id', params: department_params},  
                              {input: :employment_status, params: {as: :select, label: 'employment_status', collection: LECTURER_EMPLOYMENT_STATUS.collect(&:reverse), prompt: :true}}, 
                              {input: :activity_status, params: {as: :select, label: 'active_status', collection: LECTURER_ACTIVE_STATUS.collect(&:reverse), prompt: :true}}, 
                              :birth_date, 
                              'user.email',
                              :birth_place, 
                              {input: :gender, params: {as: :select, label: 'gender', collection: GENDER.collect(&:reverse), prompt: :true}}, 
                              :certification_number ] 

export_attributes

value: Array of Object. Object can be string or symbol
default: nil,
description:
    Menyertakan fitur export pdf dan excel dengan menspesifikasikan attribut yang ingin di-sertakan

example:

  [:nip, :name, 'department', :nidn, :certification_number, 'user.email']

add_form_remote

value: boolean
default: false
description:
    Menghidupkan form ajax pada button tambah jika true

rtc_empty_data_message

value: string
default: sanitize "Data #{t(rtc_controller_name)} kosong"
description:
    Text yang ditampilkan pada tabel jika data kosong. text dapat dalam format html

search_key

value: string
default: 'q'
description:
    Param key yang dibutuhkan pada fitur pencarian menggunakan gem ransack. Jika tidak menggunakan ransack, pada controller tidak perlu memiliki instance @q

rtc_button_new

value: boolean
default: true
description:
    Render default button new if true

rtc_actions

value: Element or Array of Element
default: nil
description:
    Render element(s) side by side with button new

toggle_view

value: boolean
default: false
description:
    render toggle rtc view. thumbnail/list

table_title

value: string
default: controller_name
description:
    Render table title

rtc_selection_checkbox (To be developed) recapitulation_matrix (removed from rtc component to dedicated component)

CONTOH KASUS:

Kasus normal

Menampilkan rtc berupa list page pada halaman index controller PagesController atau PagesController#index. RTC yang ingin ditampilkan secara lengkap (memiliki fitur advanced search dan export pdf & xls)

Yang perlu dilakukan:

  1. Controller: Pada PagesController pages_controller.rb dalam method index harus memiliki instance @q dan @pages repond dengan respond_to_remote :index, @pages

    def index
    ...
    @q = Page.search(params[:q])
    @pages = rich_table_component @q.result
    respond_to_remote :index, @pages
    end
    
  2. View: Pada view/pages/index.html.haml

    = render 'shared/rtc/component', 
    headers: [:title, :body, ['author.name', 'author'], 'author.email', nil], 
    columns_width: [2, 6, 1, 1, 1],
    search_constraint: :title_or_body_or_author_name_or_author_email_cont, 
    add_form_remote: true, 
    export_attributes: [:title, :body, ['author.name', 'author'], 'author.email'],
    advanced_search_attributes: [ :title, 
                                :body,
                                'author.name',
                                'author.email',
                                'author.address.city.name']
    
  3. View: Pada view/pages/_page.html.haml

    // Jumlah td disesuaikan dengan jumlah element pada headers, untuk kasus ini berjumlah 5
    %tr
    %td
    = page.title
    %td
    = page.body
    %td
    = page.author.name
    %td
    = page.author.email
    %td
    = link_to delete .....
    

Kasus me-render partial custom yang berbeda

Secara default baris yang dirender adalah _model.html.haml, misal _page.html.haml untuk merender partial yang berbeda untuk model page misalnya: _subscriber_page.html.haml dapat dilakukan dengan mendefinisikan parameter rtc_partial dengan lokasi file partial tersebut pages/subscriber_page

= render 'shared/rtc/component', 
  headers: [:title, :body, ['author.name', 'author'], 'author.email', nil], 
  columns_width: [2, 6, 1, 1, 1],
  search_constraint: :title_or_body_or_author_name_or_author_email_cont, 
  rtc_partial: 'pages/subscriber_page'

Jika pada rtc terdapat button tambah, edit, atau apapun yang mengharuskan merender kembali partial custom, maka tambahkan params rtc_partial pada: form: hidden_field_tag 'rtc_partial', 'home/lecturer_academic_term'

atau pada controller: params[:rtc_partial] = 'home/lecturer_academic_term'

Kasus mengacu controller yang berbeda

Misal menampilkan koleksi post pada home

Controller: home#index

...
@q = Post.search(params[:q])
@posts = rich_table_component @q.result
...

View:

= render 'shared/rtc/component', 
  headers: [:title, :body, ['author.name', 'author'], 'author.email', nil], 
  columns_width: [2, 6, 1, 1, 1],
  search_constraint: :title_or_body_or_author_name_or_author_email_cont,
  rtc_controller_name: 'posts'

Kasus dua atau lebih table dalam halaman yang sama

Misal menampilkan koleksi post pada home

Controller: home#index

def index
  ...
  @q = Post.search(params[:q])
  @posts = rich_table_component @q.result

  @p = Post.search(params[:p], search_key: :p)
  @second_posts = rich_table_component @p.result

  @r = Post.search(params[:r], search_key: :r)
  @third_posts = rich_table_component @p.result
  ...
end

View:

  = render 'shared/rtc/component', 
    headers: [:title, :body, ['author.name', 'author'], 'author.email', nil], 
    columns_width: [2, 6, 1, 1, 1],
    search_constraint: :title_or_body_or_author_name_or_author_email_cont,
    rtc_controller_name: 'posts'
  = render 'shared/rtc/component', 
    headers: [:title, :body, ['author.name', 'author'], 'author.email', nil], 
    columns_width: [2, 6, 1, 1, 1],
    search_constraint: :title_or_body_or_author_name_or_author_email_cont,
    rtc_controller_name: 'second_posts',
    rtc_partial: 'posts/second_post',
    search_key: 'p'
  = render 'shared/rtc/component', 
    headers: [:title, :body, ['author.name', 'author'], 'author.email', nil], 
    columns_width: [2, 6, 1, 1, 1],
    search_constraint: :title_or_body_or_author_name_or_author_email_cont,
    rtc_controller_name: 'third_posts',
    rtc_partial: 'posts/third_post',
    search_key: 'r'

Kasus updating tapi bukan dari tombol edit standar (misal: approve/reject)

tambahkan class html '.edit' pada button custom pada method terakhir yang terpanggil sebelum baris terupdate, harus respond remote to :update, dan harus memiliki params[:rtc_partial] yang diassign di controller ATAU dilempar dari form ATAU button edit

  • assign di controller: params[:rtc_partial] = 'admin/departments/student'
  • assign pada form (jika melewati modal form, seperti edit pada umumnya)
simple_form_for ... do |f|
  = hidden_field_tag 'rtc_partial', 'admin/departments/student'
  ...
end
  • assign dari button (jika tidak melewati modal) ruby = link_to 'approve', approve_post_path(post, rtc_partial: 'admin/departments/student'), remote: :true, class: 'btn edit'

Jika model yang diupdate berbeda dengan model controllernya, misal mengupdate post pada halaman UsersController#show, sertakan rtc_controller_name berdampingan dengan rtc_partial, contoh: link_to 'approve', approve_post_path(post, rtc_controller_name: 'admin/departments/student', rtc_partial: 'admin/departments/student'), remote: :true, class: 'btn edit'

a. Aksi tidak memunculkan modal, tetapi langsung update. Dengan custom method, model yang diupdate sesuai dengan controller

View: tambahkan class html '.edit' pada button custom

...
= link_to 'approve', approve_post_path(post), remote: :true, class: 'btn edit'
...

Controller

...
def approve
  # updating post
  @post = Post.find(params[:id])
  ...
  respond_to do |format|
    if @post.update_attributes(params[:post])
      format_remote format, :update, @post
    else
      format_remote format, :edit, @post
    end
  end
end
... 

b. Aksi tidak memunculkan modal, tetapi langsung update. Dengan custom method, model yang diupdate BERBEDA dengan controller. rtc_controller_name & rtc_partial langsung ditambahkan pada link

View: tambahkan class html '.edit' pada button custom

...
= link_to 'approve', approve_post_path(post, rtc_controller_name: 'posts', rtc_partial: 'users/post'), remote: :true, class: 'btn edit'
...

Controller

...
def approve
  # updating post
  @post = Post.find(params[:id])
  ...
  respond_to do |format|
    if @post.update_attributes(params[:post])
      format_remote format, :update, @post
    else
      format_remote format, :edit, @post
    end
  end
end
... 
  • register mime xls
  • create ability.rb
  • define current_user in application_controller if not using devise, then set as helper_method
  • define method is? in user.rb

  • rtc_button_new hanya true, false

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request