- Keep most logic out of the views, no one wants to go through a view with a 100 if statements.
- Keep it DRY.
The first thing to do is create a partial that will render the tables. This is not included in the gem because this will differ for each application.
Example:
<header>
<% table.table_actions.each do |table_action| %>
<%= button_to table_action.label, table_action.path %>
<% end %>
</header>
<table id="<%= table.name %>">
<tr>
<% table.columns.each do |column| %>
<th class="<%= column.type %>"><%= column.label %></th>
<% end %>
<th>-</th>
</tr>
<% table.resources.each do |resource| %>
<tr id="resource-<%= resource.id %>">
<% table.columns.each do |column| %>
<td class="<%= column.type %>">
<%= link_to column.path_for(resource) do %>
<%= column.value_for(resource) %>
<% end %>
</td>
<% end %>
<td>
<% table.resource_actions.each do |resource_action| %>
<%= link_to resource_action.label, resource_action.path.call(resource) %>
<% end %>
</td>
</tr>
<% end %>
</table>create a table object in for example app/table_objects/
class UserTable < TableObject::Base
self.default_path = ->(user) { url_helper.user_path(user) }
column :email,
type: :email,
path: ->(user) { user.email }
column :name,
value_method: ->(user) { "#{user.first_name} #{user.last_name}" }
column :birth_date
column :log_in_count
table_action :new,
label: 'NEW',
path: url_helper.new_user_path
resource_action :edit,
label: 'EDIT',
path: ->(user) { url_helper.edit_user_path(user) }
resource_action :destroy,
label: 'DESTROY',
path: ->(user) { url_helper.user_path(user) },
method: :destroy
end.default_path: if table has a default path this will be used for all columns, unless they have a path assigned..model_class: by default this will try to guess the model class based on the table name by removing the "Table" substring. UserTable => User.default_path: this path will be filled in all columns of the table by default. can be overridden by given your column a path..column: Will create a column object for the table..table_action: Will create action object for the table. This are actions that have to do with the table as a whole. New, Export, ....resource_action: Will create action object for the table. this are actions that have to do with the resource. Edit, Show, Destroy- The type on a column, if not given, is filled in by default based on db info. This uses
model_class. #name: by default this is the table class name in snakecase, but can be set.#resources: This is what you pass in the table. this can be collection of users, books, movies,...
#value_for(resource): If a lambda is given forvalue_method, this will be called. If novalue_methodis present it will public_send the column name on the given resource.#path_for(resrouce): Will return the path for the given resource.- custom options: All options are stored
optionshash. You can also call these as if they where attributes. Example:test_column = TableObject::Column.new(:test_column, 'test?' => true); test_column.test? # => true
- This object is used for table_actions and resource_actions.
- Also has custom options like columns
class UsersController < ApplicationController
def index
users = User.all
@user_table = UserTable.new(users)
end
end<%= render 'shared/table', table: @user_table %>If you access attributes from nested relationships you can create N+1 queries. Prevent these by using include or eager_load.
For more info you can read this
def index
users = User.includes(:address)
@user_table = UserTable.new(users)
endAdd this line to your application's Gemfile:
gem 'table_object'And then execute:
$ bundleOr install it yourself as:
$ gem install table_objectThe gem is available as open source under the terms of the MIT License.