Skip to content

Commit

Permalink
Don't hard-code Administrate's URL namespace
Browse files Browse the repository at this point in the history
Problem:

Administrate requires that its dashboards be mounted at `/admin`.

In applications with an `Admin` model,
Administrate will cause an error
because it will try to define `Admin` as a module
when it's already been defined as a class.

The hard-coded namespace limits users' freedom
in defining their own URL schema,
and prevents users from mounting
multiple Administrate dashboards at once.

Solution:

Dynamically evaluate Administrate's namespace from the request's URL.
This dynamically calculated value is used for all links and redirects
in Administrate dashboards.

The namespace is now only set by generators.
If a user wants to change their namespace
away from the default of `admin`,
they must run the generators and manually change `admin`
to the namespace of their choice.

Next Steps:

Change generators to accept
(or read from some configuration file)
an optional namespace argument
instead of always using the `admin` namespace.
  • Loading branch information
c-lliope committed Dec 16, 2015
1 parent 09b3883 commit 2aca8bb
Show file tree
Hide file tree
Showing 22 changed files with 51 additions and 43 deletions.
7 changes: 4 additions & 3 deletions app/controllers/administrate/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def create

if resource.save
redirect_to(
[Administrate::NAMESPACE, resource],
[namespace, resource],
notice: translate_with_resource("create.success"),
)
else
Expand All @@ -50,7 +50,7 @@ def create
def update
if requested_resource.update(resource_params)
redirect_to(
[Administrate::NAMESPACE, requested_resource],
[namespace, requested_resource],
notice: translate_with_resource("update.success"),
)
else
Expand Down Expand Up @@ -105,7 +105,8 @@ def permitted_attributes
dashboard.permitted_attributes
end

delegate :resource_class, :resource_name, to: :resource_resolver
delegate :resource_class, :resource_name, :namespace, to: :resource_resolver
helper_method :namespace

def resource_resolver
@_resource_resolver ||=
Expand Down
6 changes: 3 additions & 3 deletions app/views/administrate/application/_collection.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ to display a collection of resources in an HTML table.
<tr class="table__row"
role="link"
tabindex="0"
data-url="<%= polymorphic_path([Administrate::NAMESPACE, resource]) -%>"
data-url="<%= polymorphic_path([namespace, resource]) -%>"
>
<% collection_presenter.attributes_for(resource).each do |attribute| %>
<td class="cell-data cell-data--<%= attribute.html_class %>">
Expand All @@ -57,13 +57,13 @@ to display a collection of resources in an HTML table.

<td><%= link_to(
t("administrate.actions.edit"),
[:edit, Administrate::NAMESPACE, resource],
[:edit, namespace, resource],
class: "action-edit",
) %></td>

<td><%= link_to(
t("administrate.actions.destroy"),
[Administrate::NAMESPACE, resource],
[namespace, resource],
class: "table__action--destroy",
method: :delete,
data: { confirm: t("administrate.actions.confirm") }
Expand Down
2 changes: 1 addition & 1 deletion app/views/administrate/application/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ and renders all form fields for a resource's editable attributes.
[1]: http://www.rubydoc.info/gems/administrate/Administrate/Page/Form
%>

<%= form_for([Administrate::NAMESPACE, page.resource], html: { class: "form" }) do |f| %>
<%= form_for([namespace, page.resource], html: { class: "form" }) do |f| %>
<% if page.resource.errors.any? %>
<div id="error_explanation">
<h2>
Expand Down
2 changes: 1 addition & 1 deletion app/views/administrate/application/_sidebar.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ as defined by the DashboardManifest.
<li>
<%= link_to(
display_resource_name(resource),
[Administrate::NAMESPACE, resource],
[namespace, resource],
class: "sidebar__link sidebar__link--#{nav_link_state(resource)}"
) %>
</li>
Expand Down
2 changes: 1 addition & 1 deletion app/views/administrate/application/edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ It displays a header, and renders the `_form` partial to do the heavy lifting.
<div class="header-actions">
<%= link_to(
"Show #{page.page_title}",
[Administrate::NAMESPACE, page.resource],
[namespace, page.resource],
class: "button",
) %>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/views/administrate/application/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ It renders the `_table` partial to display details about the resources.
<div class="header-actions">
<%= link_to(
"New #{page.resource_name.titleize.downcase}",
[:new, Administrate::NAMESPACE, page.resource_name],
[:new, namespace, page.resource_name],
class: "button",
) %>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/views/administrate/application/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ as well as a link to its edit page.
<div class="header-actions">
<%= link_to(
"Edit",
[:edit, Administrate::NAMESPACE, page.resource],
[:edit, namespace, page.resource],
class: "button",
) %>
</div>
Expand Down
2 changes: 1 addition & 1 deletion app/views/fields/belongs_to/_index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ By default, the relationship is rendered as a link to the associated object.
<% if field.data %>
<%= link_to(
field.display_associated_resource,
[Administrate::NAMESPACE, field.data],
[namespace, field.data],
) %>
<% end %>
2 changes: 1 addition & 1 deletion app/views/fields/belongs_to/_show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ By default, the relationship is rendered as a link to the associated object.
<% if field.data %>
<%= link_to(
field.display_associated_resource,
[Administrate::NAMESPACE, field.data],
[namespace, field.data],
) %>
<% end %>
2 changes: 1 addition & 1 deletion app/views/fields/has_one/_index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ By default, the relationship is rendered as a link to the associated object.
<% if field.data %>
<%= link_to(
field.display_associated_resource,
[Administrate::NAMESPACE, field.data],
[namespace, field.data],
) %>
<% end %>
2 changes: 1 addition & 1 deletion app/views/fields/has_one/_show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ By default, the relationship is rendered as a link to the associated object.
<% if field.data %>
<%= link_to(
field.display_associated_resource,
[Administrate::NAMESPACE, field.data],
[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 @@ -19,6 +19,6 @@ By default, the relationship is rendered as a link to the associated object.
<% if field.data %>
<%= link_to(
field.display_associated_resource,
[Administrate::NAMESPACE, field.data]
[namespace, field.data]
) %>
<% end %>
2 changes: 1 addition & 1 deletion app/views/fields/polymorphic/_show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ By default, the relationship is rendered as a link to the associated object.
<% if field.data %>
<%= link_to(
field.display_associated_resource,
[Administrate::NAMESPACE, field.data],
[namespace, field.data],
) %>
<% end %>
1 change: 0 additions & 1 deletion lib/administrate/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
require "selectize-rails"
require "sprockets/railtie"

require "administrate/namespace"
require "administrate/page/form"
require "administrate/page/show"
require "administrate/page/collection"
Expand Down
3 changes: 0 additions & 3 deletions lib/administrate/namespace.rb

This file was deleted.

8 changes: 5 additions & 3 deletions lib/administrate/resource_resolver.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
require "administrate/namespace"

module Administrate
class ResourceResolver
def initialize(controller_path)
Expand All @@ -10,6 +8,10 @@ def dashboard_class
Object.const_get(resource_class_name + "Dashboard")
end

def namespace
controller_path.split("/").first
end

def resource_class
Object.const_get(resource_class_name)
end
Expand All @@ -33,7 +35,7 @@ def model_path_parts
end

def controller_path_parts
controller_path.singularize.split("/") - [Administrate::NAMESPACE.to_s]
controller_path.singularize.split("/")[1..-1]
end

attr_reader :controller_path
Expand Down
4 changes: 2 additions & 2 deletions spec/administrate/views/fields/has_one/_index_spec.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require "rails_helper"

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

Expand All @@ -26,7 +26,7 @@

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

expected = "<a href=\"#{product_path}\">#{product.name}</a>"
Expand Down
4 changes: 2 additions & 2 deletions spec/administrate/views/fields/has_one/_show_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
require "administrate/fields/has_one"

describe "fields/has_one/_show", type: :view do
context "without an associated records" do
context "without an associated record" do
it "displays nothing" do
has_one = instance_double(
"Administrate::Field::HasOne",
Expand Down Expand Up @@ -31,7 +31,7 @@

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

expected = "<a href=\"#{product_path}\">#{product.name}</a>"
Expand Down
2 changes: 1 addition & 1 deletion spec/administrate/views/fields/polymorphic/_index_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

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

expected = "<a href=\"#{product_path}\">#{product.name}</a>"
Expand Down
2 changes: 1 addition & 1 deletion spec/administrate/views/fields/polymorphic/_show_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@

render(
partial: "fields/polymorphic/show.html.erb",
locals: { field: polymorphic },
locals: { field: polymorphic, namespace: "admin" },
)

expected = "<a href=\"#{product_path}\">#{product.name}</a>"
Expand Down
33 changes: 21 additions & 12 deletions spec/lib/administrate/resource_resolver_spec.rb
Original file line number Diff line number Diff line change
@@ -1,50 +1,59 @@
require "spec_helper"
require "active_support/core_ext/string/inflections"
require "support/constant_helpers"
require "administrate/resource_resolver"

describe Administrate::ResourceResolver do
describe "#resource_class" do
describe "#dashboard_class" do
it "handles global-namepsace models" do
begin
class User; end
class UserDashboard; end
resolver = Administrate::ResourceResolver.new("admin/users")

expect(resolver.resource_class).to eq(User)
expect(resolver.dashboard_class).to eq(UserDashboard)
ensure
remove_constants :User
remove_constants :UserDashboard
end
end

it "handles namespaced models" do
begin
module Blog; class Post; end; end
module Blog; class PostDashboard; end; end
resolver = Administrate::ResourceResolver.new("admin/blog/posts")

expect(resolver.resource_class).to eq(Blog::Post)
expect(resolver.dashboard_class).to eq(Blog::PostDashboard)
ensure
remove_constants :Blog
end
end
end

describe "#dashboard_class" do
describe "#namespace" do
it "returns the top-level namespace" do
resolver = Administrate::ResourceResolver.new("foobar/user")

expect(resolver.namespace).to eq("foobar")
end
end

describe "#resource_class" do
it "handles global-namepsace models" do
begin
class UserDashboard; end
class User; end
resolver = Administrate::ResourceResolver.new("admin/users")

expect(resolver.dashboard_class).to eq(UserDashboard)
expect(resolver.resource_class).to eq(User)
ensure
remove_constants :UserDashboard
remove_constants :User
end
end

it "handles namespaced models" do
begin
module Blog; class PostDashboard; end; end
module Blog; class Post; end; end
resolver = Administrate::ResourceResolver.new("admin/blog/posts")

expect(resolver.dashboard_class).to eq(Blog::PostDashboard)
expect(resolver.resource_class).to eq(Blog::Post)
ensure
remove_constants :Blog
end
Expand Down
2 changes: 1 addition & 1 deletion spec/support/table.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def clickable_table_elements

def url_for(model)
"/" + [
Administrate::NAMESPACE,
:admin,
model.class.to_s.underscore.pluralize,
model.to_param,
].join("/")
Expand Down

0 comments on commit 2aca8bb

Please sign in to comment.