Skip to content

Commit

Permalink
Improve resource display API & default behavior
Browse files Browse the repository at this point in the history
Problem:

Administrate relies on `#to_s`
to display resources throughout the system.
In order to get Administrate working correctly,
developers must define `#to_s` on all models
that will be displayed in the admin dashboard.

This process is not documented,
can be confusing,
and gets in the way of a zero-configuration dashboard.

Solution:

Add `Administrate::BaseDashboard#display_resource`,
which takes a resource and returns a sensible string representation.
Devs can overwrite this method on a per-dashboard basis
to customize how their resources are displayed.

Add generated comment for `display_resource`, that looks like:

```
  # Overwrite this method to customize how line items are displayed
  # across all pages of the admin dashboard.
  #
  # def display_resource(line_item)
  #   "LineItem ##{line_item.id}"
  # end
```

Minor changes:

Extract `Administrate::Field::Associative` as a superclass,
which contains logic for looking up associated dashboards
and associated models' classes.

Fix PR suggestions
  • Loading branch information
c-lliope committed Nov 12, 2015
1 parent fc3f4c3 commit fcd3fc7
Show file tree
Hide file tree
Showing 54 changed files with 299 additions and 112 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@

### Upcoming Release

* [#191] [CHANGE] Improve API for specifying how resources are displayed
across the dashboard.
* Models are now displayed with a sensible default - (e.g. "User #2")
* Users can define `ModelDashboard#display_resource(resource)` for custom
display behavior
* Users who have generated views for the following field types
may need to update them to take advantage of the new API:
* HasOne
* HasMany
* PolyMorphic
* BelongsTo
* [#223] [FEATURE] Translation: Vietnamese
* [#161] [FEATURE] Translation: Mandarin Chinese
* [#196] [FEATURE] Translation: Taiwanese Mandarin
Expand Down
9 changes: 3 additions & 6 deletions app/views/fields/belongs_to/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ that displays all possible records to associate with.
%>

<%= f.label field.permitted_attribute %>
<%= f.collection_select(
field.permitted_attribute,
field.candidate_records,
:id,
:to_s,
) %>
<%= f.select(field.permitted_attribute) do %>
<%= options_for_select(field.associated_resource_options) %>
<% end %>
5 changes: 4 additions & 1 deletion app/views/fields/belongs_to/_index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ By default, the relationship is rendered as a link to the associated object.
%>

<% if field.data %>
<%= link_to field.data, [Administrate::NAMESPACE, field.data] %>
<%= link_to(
field.display_associated_resource,
[Administrate::NAMESPACE, field.data],
) %>
<% end %>
5 changes: 4 additions & 1 deletion app/views/fields/belongs_to/_show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ By default, the relationship is rendered as a link to the associated object.
%>

<% if field.data %>
<%= link_to field.data, [Administrate::NAMESPACE, field.data] %>
<%= link_to(
field.display_associated_resource,
[Administrate::NAMESPACE, field.data],
) %>
<% end %>
12 changes: 3 additions & 9 deletions app/views/fields/has_many/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,6 @@ and is augmented with [Selectize].

<%= f.label field.attribute_key %>

<%= f.collection_select(
field.attribute_key,
field.candidate_records,
:id,
:to_s,
{},
{ multiple: true },
)
%>
<%= f.select(field.attribute_key, nil, {}, multiple: true) do %>
<%= options_for_select(field.associated_resource_options) %>
<% end %>
2 changes: 1 addition & 1 deletion app/views/fields/has_one/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ so this partial renders a message to that effect.
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Field/HasOne
%>

<%= f.label field.permitted_attribute %>
<%= f.label field.attribute %>

<%= t("administrate.fields.has_one.not_supported") %>
5 changes: 4 additions & 1 deletion app/views/fields/has_one/_index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ By default, the relationship is rendered as a link to the associated object.
%>

<% if field.data %>
<%= link_to field.data, [Administrate::NAMESPACE, field.data] %>
<%= link_to(
field.display_associated_resource,
[Administrate::NAMESPACE, field.data],
) %>
<% end %>
5 changes: 4 additions & 1 deletion app/views/fields/has_one/_show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,8 @@ By default, the relationship is rendered as a link to the associated object.
%>

<% if field.data %>
<%= link_to field.data, [Administrate::NAMESPACE, field.data] %>
<%= link_to(
field.display_associated_resource,
[Administrate::NAMESPACE, field.data],
) %>
<% end %>
2 changes: 1 addition & 1 deletion app/views/fields/polymorphic/_index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ By default, the relationship is rendered as a link to the associated object.

<% if field.data %>
<%= link_to(
field.data.to_s,
field.display_associated_resource,
polymorphic_path([:admin, field.data])
) %>
<% end %>
4 changes: 2 additions & 2 deletions app/views/fields/polymorphic/_show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ By default, the relationship is rendered as a link to the associated object.

<% if field.data %>
<%= link_to(
field.data.to_s,
polymorphic_path([:admin, field.data])
field.display_associated_resource,
[:admin, field.data],
) %>
<% end %>
4 changes: 4 additions & 0 deletions lib/administrate/base_dashboard.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,9 @@ def show_page_attributes
def collection_attributes
self.class::COLLECTION_ATTRIBUTES
end

def display_resource(resource)
"#{resource.class} ##{resource.id}"
end
end
end
25 changes: 25 additions & 0 deletions lib/administrate/fields/associative.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
require_relative "base"

module Administrate
module Field
class Associative < Base
def display_associated_resource
associated_dashboard.display_resource(data)
end

protected

def associated_dashboard
"#{associated_class_name}Dashboard".constantize.new
end

def associated_class
associated_class_name.constantize
end

def associated_class_name
options.fetch(:class_name, attribute.to_s.singularize.camelcase)
end
end
end
end
1 change: 1 addition & 0 deletions lib/administrate/fields/base.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
require_relative "deferred"
require "active_support/core_ext/string/inflections"

module Administrate
module Field
Expand Down
18 changes: 12 additions & 6 deletions lib/administrate/fields/belongs_to.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
require_relative "base"
require_relative "associative"

module Administrate
module Field
class BelongsTo < Field::Base
class BelongsTo < Associative
def self.permitted_attribute(attr)
:"#{attr}_id"
end
Expand All @@ -11,14 +11,20 @@ def permitted_attribute
self.class.permitted_attribute(attribute)
end

def candidate_records
Object.const_get(associated_class_name).all
def associated_resource_options
candidate_resources.map do |resource|
[display_candidate_resource(resource), resource.id]
end
end

private

def associated_class_name
options.fetch(:class_name, attribute.to_s.camelcase)
def candidate_resources
associated_class.all
end

def display_candidate_resource(resource)
associated_dashboard.display_resource(resource)
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/administrate/fields/date_time.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require_relative "base"

module Administrate
module Field
class DateTime < Base
Expand Down
2 changes: 2 additions & 0 deletions lib/administrate/fields/deferred.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require "active_support/core_ext/module/delegation"

module Administrate
module Field
class Deferred
Expand Down
18 changes: 10 additions & 8 deletions lib/administrate/fields/has_many.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
require_relative "base"
require_relative "associative"
require "administrate/page/collection"

module Administrate
module Field
class HasMany < Field::Base
class HasMany < Associative
DEFAULT_LIMIT = 5

def self.permitted_attribute(attribute)
Expand All @@ -18,8 +18,10 @@ def attribute_key
permitted_attribute.keys.first
end

def candidate_records
Object.const_get(associated_class_name).all
def associated_resource_options
candidate_resources.map do |resource|
[display_candidate_resource(resource), resource.id]
end
end

def limit
Expand All @@ -40,12 +42,12 @@ def more_than_limit?

private

def associated_dashboard
Object.const_get("#{associated_class_name}Dashboard").new
def candidate_resources
associated_class.all
end

def associated_class_name
options.fetch(:class_name, attribute.to_s.singularize.camelcase)
def display_candidate_resource(resource)
associated_dashboard.display_resource(resource)
end
end
end
Expand Down
5 changes: 2 additions & 3 deletions lib/administrate/fields/has_one.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
require_relative "base"
require_relative "belongs_to"
require_relative "associative"

module Administrate
module Field
class HasOne < BelongsTo
class HasOne < Associative
def self.permitted_attribute(attr)
attr
end
Expand Down
4 changes: 2 additions & 2 deletions lib/administrate/fields/polymorphic.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
require_relative "base"
require_relative "associative"

module Administrate
module Field
class Polymorphic < Base
class Polymorphic < Associative
end
end
end
2 changes: 1 addition & 1 deletion lib/administrate/page/form.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def attributes
end

def page_title
resource.to_s
dashboard.display_resource(resource)
end

protected
Expand Down
2 changes: 1 addition & 1 deletion lib/administrate/page/show.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def initialize(dashboard, resource)
attr_reader :resource

def page_title
resource.to_s
dashboard.display_resource(resource)
end

def attributes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,11 @@ class <%= class_name %>Dashboard < Administrate::BaseDashboard
end.join("\n")
%>
]

# Overwrite this method to customize how <%= file_name.pluralize.humanize.downcase %> are displayed
# across all pages of the admin dashboard.
#
# def display_resource(<%= file_name %>)
# "<%= class_name %> ##{<%= file_name %>.id}"
# end
end
37 changes: 37 additions & 0 deletions spec/administrate/views/fields/has_one/_form_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
require "rails_helper"
require "administrate/fields/has_one"

describe "fields/has_one/_form", type: :view do
it "displays the field name" do
has_one = instance_double(
"Administrate::Field::HasOne",
attribute: "Commentable",
)

render(
partial: "fields/has_one/form.html.erb",
locals: { field: has_one, f: form_builder },
)

expect(rendered.strip).to include("Commentable")
end

it "does not display a form" do
has_one = instance_double(
"Administrate::Field::HasOne",
attribute: "Commentable",
)

render(
partial: "fields/has_one/form.html.erb",
locals: { field: has_one, f: form_builder },
)

expect(rendered).
to include(t("administrate.fields.has_one.not_supported"))
end

def form_builder
double("Form Builder", label: "Commentable")
end
end
36 changes: 36 additions & 0 deletions spec/administrate/views/fields/has_one/_index_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require "rails_helper"

describe "fields/has_one/_index", type: :view do
context "without an associated records" do
it "displays nothing" do
has_one = double(data: nil)

render(
partial: "fields/has_one/index.html.erb",
locals: { field: has_one },
)

expect(rendered.strip).to eq("")
end
end

context "with an associated record" do
it "renders a link to the record" do
product = create(:product)
product_path = polymorphic_path([:admin, product])
has_one = instance_double(
"Administrate::Field::HasOne",
data: product,
display_associated_resource: product.name,
)

render(
partial: "fields/has_one/index.html.erb",
locals: { field: has_one },
)

expected = "<a href=\"#{product_path}\">#{product.name}</a>"
expect(rendered.strip).to eq(expected)
end
end
end
Loading

0 comments on commit fcd3fc7

Please sign in to comment.