README.md in admino-0.0.5 vs README.md in admino-0.0.6
- old
+ new
@@ -45,11 +45,11 @@
```ruby
class TasksQuery < Admino::Query::Base
end
```
-Each query object gets initialized with a hash of params, and features a `#scope` method that returns the filtered/sorted result set. As you may have guessed, query objects can be great companions to index controller actions:
+Each query object gets initialized with a hash of params, and features a `#scope` method that returns the filtered/sorted result set. As you may have guessed, query objects can be great companions to index actions:
```ruby
class TasksController < ApplicationController
def index
@query = TasksQuery.new(params)
@@ -84,12 +84,11 @@
class TasksQuery < Admino::Query::Base
# ...
search_field :title_matches
end
```
-The `#scope` method will check the presence of the `params[:query][:title_matches]` key. If it finds it, it will augment the query with a
-named scope called `:title_matches`, expected to be found within the `Task` model, that needs to accept an argument.
+The `#scope` method will check the presence of the `params[:query][:title_matches]` key. If it finds it, it will augment the query with a named scope called `:title_matches`, expected to be found within the `Task` model. The scope needs to accept an argument.
```ruby
class Task < ActiveRecord::Base
scope :title_matches, ->(text) {
where('title ILIKE ?', "%#{text}%")
@@ -110,11 +109,11 @@
# ...
filter_by :status, [:completed, :pending]
end
```
-Just like a search field, with a declared filter group the `#scope` method will check the presence of a `params[:query][:status]` key. If it finds it (and its value corresponds to one of the declared scopes) it will augment the query the scope itself:
+Just like a search field, with a declared filter group the `#scope` method will check the presence of a `params[:query][:status]` key. If it finds it (and its value corresponds to one of the declared scopes) it will augment the query with the scope itself:
```ruby
class Task < ActiveRecord::Base
scope :completed, -> { where(completed: true) }
scope :pending, -> { where(completed: false) }
@@ -248,37 +247,26 @@
### Simple Form support
The presenter also offers a `#simple_form` method to make it work with [Simple Form](https://github.com/plataformatec/simple_form) out of the box.
-### I18n
+### Output customization
-To localize the search form labels, as well as the group filter names and scope links, please refer to the following YAML file:
+The `#scope_link` methods are very flexible, allowing you to change almost every aspect of the generated links:
-```yaml
-en:
- query:
- attributes:
- tasks_query:
- title_matches: 'Title contains'
- filter_groups:
- tasks_query:
- status:
- name: 'Filter by status'
- scopes:
- completed: 'Completed'
- pending: 'Pending'
- sorting_scopes:
- task_query:
- by_due_date: 'By due date'
- by_title: 'By title'
+```erb
+<% status_filter = query.filter_group_by_name(:status) %>
+
+<%= status_filter.scope_link :completed,
+ 'Custom title',
+ active_class: 'active',
+ class: 'custom-class'
+%>
```
-### Output customization
+Please refer to the tests for the details.
-The presenter supports a number of optional arguments that allow a great amount of flexibility regarding customization of CSS classes, labels and HTML attributes. Please refer to the tests for the details.
-
### Overwriting the starting scope
Suppose you have to filter the tasks based on the `@current_user` work group. You can easily provide an alternative starting scope from the controller passing it as an argument to the `#scope` method:
```ruby
@@ -288,48 +276,79 @@
end
```
### Coertions
-Admino can perform automatic coertions from a param string input to the type needed by the model named scope:
+Suppose the presence of a model scope that requires a non-textual argument (ie. a date):
```ruby
+class Task < ActiveRecord::Base
+ scope :due_date_from, ->(date) { where('due_date >= ?', date) }
+end
+```
+
+Admino can perform some automatic coertions to the textual parameter it gets, and pass the coerced value to the scope:
+
+```ruby
class TasksQuery < Admino::Query::Base
- # ...
- field :due_date_from, coerce: :to_date
- field :due_date_to, coerce: :to_date
+ search_field :due_date_from, coerce: :to_date
end
+
+query = TaskQuery.new(query: { due_date_from: '2014-03-01' })
+query.search_field_by_name(:due_date_from).value # => #<Date Sat, 01 Mar 2014>
```
-The following coertions are available:
+If a specific coercion cannot be performed with the provided input, the scope won't be chained. The following coertions are available:
+
* `:to_boolean`
* `:to_constant`
* `:to_date`
* `:to_datetime`
* `:to_decimal`
* `:to_float`
* `:to_integer`
* `:to_symbol`
* `:to_time`
-If a specific coercion cannot be performed with the provided input, the scope won't be chained.
-
Please see the [`Coercible::Coercer::String`](https://github.com/solnic/coercible/blob/master/lib/coercible/coercer/string.rb) class for details.
### Default sorting
-If you need to setup a default sorting, you can pass some optional arguments to a `scoping` declaration:
+If you need to setup a default sorting, you can pass some optional arguments to the `sorting` declaration:
```ruby
class TasksQuery < Admino::Query::Base
# ...
sorting :by_due_date, :by_title,
default_scope: :by_due_date,
default_direction: :desc
end
```
+### I18n
+
+To localize the search form labels, as well as the group filter names and scope links, please refer to the following YAML file:
+
+```yaml
+en:
+ query:
+ attributes:
+ tasks_query:
+ title_matches: 'Title contains'
+ filter_groups:
+ tasks_query:
+ status:
+ name: 'Filter by status'
+ scopes:
+ completed: 'Completed'
+ pending: 'Pending'
+ sorting_scopes:
+ task_query:
+ by_due_date: 'By due date'
+ by_title: 'By title'
+```
+
## Admino::Table::Presenter
Admino offers a [Showcase collection presenter](https://github.com/stefanoverna/showcase) that makes it really easy to generate HTML tables from a set of records:
```erb
@@ -346,29 +365,29 @@
<table>
<thead>
<tr>
<th role='title'>Title</th>
<th role='completed'>Completed</th>
- <th role='due_date'>Due date</th>
+ <th role='due-date'>Due date</th>
</tr>
<thead>
<tbody>
<tr id='task_1' class='is-even'>
<td role='title'>Call mum ASAP</td>
<td role='completed'>✓</td>
- <td role='due_date'>2013-02-04</td>
+ <td role='due-date'>2013-02-04</td>
</tr>
<tr id='task_2' class='is-odd'>
<!-- ... -->
</tr>
<tbody>
</table>
```
### Record actions
-Often table rows needs to offer some kind of action associated with the record. The presenter implements the following DSL to support that:
+Often tables need to offer some kind of action associated with the records. The presenter implements the following DSL to support that:
```erb
<%= Admino::Table::Presenter.new(@tasks, Task, self).to_html do |row, record| %>
<%# ... %>
<%= row.actions do %>
@@ -400,12 +419,20 @@
</table>
```
### Sortable columns
-Once a query object is passed to the presenter, columns can be associated to specific sorting scopes of the query object using the `sorting` option:
+If you want to make the table headers sortable, then please create an Admino query object class to define the available sorting scopes.
+```ruby
+class TaskQuery < Admino::Query::Base
+ sorting :by_title, :by_due_date
+end
+```
+
+You can then pass the query object as a parameter to the table presenter initializer, and associate table columns to specific sorting scopes of the query object using the `sorting` directive:
+
```erb
<% query = present(@query) %>
<%= Admino::Table::Presenter.new(@tasks, Task, query, self).to_html do |row, record| %>
<%= row.column :title, sorting: :by_title %>
@@ -418,24 +445,24 @@
```html
<table>
<thead>
<tr>
<th role='title'>
- <a href="/admin/tasks?sorting=by_title&sort_order=desc" class='is-asc'>Title</a>
+ <a href='/admin/tasks?sorting=by_title&sort_order=desc' class='is-asc'>Title</a>
</th>
- <th role='due_date'>
- <a href="/admin/tasks?sorting=by_due_date&sort_order=asc" class='is-asc'>Due date</a>
+ <th role='due-date'>
+ <a href='/admin/tasks?sorting=by_due_date&sort_order=asc'>Due date</a>
</th>
</tr>
<thead>
<!-- ... -->
</table>
```
### Customizing the output
-The `#column` and `#action` methods are very flexible, allowing youto change almost every aspect of the generated table cells:
+The `#column` and `#action` methods are very flexible, allowing you to change almost every aspect of the generated table cells:
```erb
<%= Admino::Table::Presenter.new(@tasks, Task, self).to_html(class: 'table-class') do |row, record| %>
<%= row.column :title, 'Custom title',
class: 'custom-class', role: 'custom-role', data: { custom: 'true' },
@@ -445,11 +472,11 @@
class: 'custom-class', role: 'custom-role', data: { custom: 'true' }
%>
<% end %>
```
-If you need more power, you can also decide to subclass `Admino::Table::Presenter`. For each HTML element, there's a set of methods you can override to customize it's appeareance.
+If you need more power, you can also subclass `Admino::Table::Presenter`. For each HTML element, there's a set of methods you can override to customize it's appeareance.
Table cells are generated through two collaborator classes: `Admino::Table::HeadRow` and `Admino::Table::ResourceRow`. You can easily replace them with a subclass if you want. To grasp the idea here's an example:
```ruby
class CustomTablePresenter < Admino::Table::Presenter
private
@@ -498,21 +525,15 @@
end
```
Please refer to the tests for all the details.
-### Inherited resources
+### Inherited resources (and similar)
-If the action URLs can be programmatically generated, it becomes even easier to specify the table actions:
+If your controller actions are generated through [Inherited Resources](https://github.com/josevalim/inherited_resources), then you can always get the URL pointing to the show action with the `resource_path` helper method. Similar helpers [are available for the other REST actions too](https://github.com/josevalim/inherited_resources#url-helpers) (new, edit, destroy).
-```erb
-<%= CustomTablePresenter.new(@tasks, Task, self).to_html do |row, record| %>
- <%# ... %>
- <%= row.actions :show, :edit, :destroy %>
-<% end %>
-```
-For instance, using [Inherited Resources](https://github.com/josevalim/inherited_resources) to generate controller actions, you can use its [helper methods](https://github.com/josevalim/inherited_resources#url-helpers) to build a custom subclass of `Admino::Table::Presenter`:
+More in general, if you are able to programmatically generate/obtain the URLs of your row actions, you can subclass `Admino::Table::Presenter` and declare them:
```ruby
class CustomTablePresenter < Admino::Table::Presenter
private
@@ -536,9 +557,18 @@
def destroy_action_html_options
{ method: :delete }
end
end
end
+```
+
+This will enable you to generate row actions even faster, simply declaring them as arguments to the `#actions` DSL method:
+
+```erb
+<%= CustomTablePresenter.new(@tasks, Task, self).to_html do |row, record| %>
+ <%# ... %>
+ <%= row.actions :show, :edit, :destroy %>
+<% end %>
```
### I18n
Column titles are generated using the model [`#human_attribute_name`](http://apidock.com/rails/ActiveRecord/Base/human_attribute_name/class) method, so if you already translated the model attribute names, you're good to go. To translate actions, please refer to the following YAML file: