Description
What would you like to be able to do? Can you provide some examples?
As a developer I can define multiple looks for a
Field
and determine which one to use when using the field.
For example, I have a dashboard with three Field::HasMany
attributes. For one of them I want to use the "default look" (the set of partials provided by administrate
) but for the other two I want to use two different "looks" defined by me.
How could we go about implementing that?
Introduce the concept of looks (or variants?). A look is a group of partials that determine how a Field
is displayed in different pages. There is a default
look provided by administrate
(the existing partials for each field) and developers can create, within their applications, as many custom looks as needed.
app/
├─ views/
│ ├─ fields/
│ │ ├─ belongs_to/
│ │ │ ├─ looks/
│ │ │ │ ├─ default/
│ │ │ │ │ ├─ _form.html.erb
│ │ │ │ │ ├─ _show.html.erb
│ │ │ │ │ ├─ _index.html.erb
│ │ ├─ has_many/
│ │ │ ├─ looks/
│ │ │ │ ├─ default/
...
Creating custom looks
A custom look is created by adding a new folder (named after the look) under app/views/fields/<field_name>/looks/
with the respective partials to render a Field. A custom look might define all or a subset of the three partials needed for a Field. In case of missing partials, the ones defined in the default look are used as fallback.
app/
├─ views/
│ ├─ fields/
│ │ ├─ belongs_to/
│ │ │ ├─ looks/
│ │ │ │ ├─ simple/
│ │ │ │ │ ├─ _index.html.erb
│ │ │ │ ├─ extended/
│ │ │ │ │ ├─ _show.html.erb
Using a custom look
To use a custom look, its name is passed as an option to a Field. If the option is not given, the default look is used.
# app/dashboards/book_dashboard.rb
ATTRIBUTE_TYPES = {
pages: Field::HasMany,
authors: Field::HasMany.with_options(look: :simple),
publishers: Field::HasMany.with_options(look: :extended)
}
# administrate/lib/administrate/field/base.rb
def to_partial_path
look = options.fetch(:look, :default)
partial_path = partial_path(page, look)
if look != :default && lookup_context.exists?(partial_path, [], true)
partial_path
else
partial_path(page, :default)
end
end
private
def partial_path(page, look)
"/fields/#{self.class.field_type}/#{look}/#{page}"
end
Can you think of other approaches to the problem?
An alternative, in my opinion less structured approach, would be to allow developers to specify the individual custom partials to be used to render a Field, through a new option (partials
or so). If no custom partials are given then the default ones are used.
- Dashboard
# app/dashboards/book_dashboard.rb
ATTRIBUTE_TYPES = {
pages: Field::HasMany,
authors: Field::HasMany.with_options(partials: { index: '/path/to/custom/partial'}),
publishers: Field::HasMany.with_options(partials: { show: '/path/to/custom/partial'})
}
- Aministrate Base field
# administrate/lib/administrate/field/base.rb
def to_partial_path
options.dig(:partials, page) || "/fields/#{self.class.field_type}/#{page}"
end
The strategy I've been using so far.
So far, whenever I need an extra "look" for a Field I create a new Field (without custom behaviour), that inherits from the respective administrate Field. Then, use the custom field in the dashboard for the attributes that need the custom look.
For example:
def HasManyExtendedView < Field::HasMany; end
def HasManySimpleView < Field::HashMany; end
# app/dashboards/book_dashboard.rb
ATTRIBUTE_TYPES = {
pages: Field::HasMany,
authors: HasManySimpleView,
publishers: HasManyExtendedView
}
This approach doesn't scale and results in having a lot of unnecessary files/code (a bunch of custom fields without custom behaviour)