diff --git a/app/assets/javascripts/administrate/components/table.js b/app/assets/javascripts/administrate/components/table.js index c283eb410d..bb9b36919a 100644 --- a/app/assets/javascripts/administrate/components/table.js +++ b/app/assets/javascripts/administrate/components/table.js @@ -2,12 +2,14 @@ $(function() { var keycodes = { space: 32, enter: 13 }; var visitDataUrl = function(event) { - if (event.type=="click" || + if (event.type == "click" || event.keyCode == keycodes.space || event.keyCode == keycodes.enter) { - if(!event.target.href) { - window.location = $(event.target).closest("tr").data("url"); + if (!event.target.href) { + var url = $(event.target).closest("tr").data("url"); + + if (url) { window.location = url; } } } }; diff --git a/app/controllers/administrate/application_controller.rb b/app/controllers/administrate/application_controller.rb index 20c3e3a242..f1992704cd 100644 --- a/app/controllers/administrate/application_controller.rb +++ b/app/controllers/administrate/application_controller.rb @@ -80,6 +80,17 @@ def nav_link_state(resource) end end + helper_method :valid_action? + def valid_action?(name, resource = resource_name) + !!routes.detect do |controller, action| + controller == resource.to_s.pluralize && action == name.to_s + end + end + + def routes + @routes ||= Namespace.new(namespace).routes + end + def records_per_page params[:per_page] || 20 end diff --git a/app/views/administrate/application/_collection.html.erb b/app/views/administrate/application/_collection.html.erb index 8a4d0932a1..1aeffe3735 100644 --- a/app/views/administrate/application/_collection.html.erb +++ b/app/views/administrate/application/_collection.html.erb @@ -47,16 +47,17 @@ to display a collection of resources in an HTML table. <% end %> <% end %> - + <% [valid_action?(:edit), valid_action?(:destroy)].count(true).times do %> + + <% end %> <% resources.each do |resource| %> > <% collection_presenter.attributes_for(resource).each do |attribute| %> @@ -68,19 +69,23 @@ to display a collection of resources in an HTML table. <% end %> - <%= link_to( - t("administrate.actions.edit"), - [:edit, namespace, resource], - class: "action-edit", - ) %> + <% if valid_action? :edit %> + <%= link_to( + t("administrate.actions.edit"), + [:edit, namespace, resource], + class: "action-edit", + ) %> + <% end %> - <%= link_to( - t("administrate.actions.destroy"), - [namespace, resource], - class: "table__action--destroy", - method: :delete, - data: { confirm: t("administrate.actions.confirm") } - ) %> + <% if valid_action? :destroy %> + <%= link_to( + t("administrate.actions.destroy"), + [namespace, resource], + class: "table__action--destroy", + method: :delete, + data: { confirm: t("administrate.actions.confirm") } + ) %> + <% end %> <% end %> diff --git a/app/views/administrate/application/edit.html.erb b/app/views/administrate/application/edit.html.erb index 4fac99aa51..99903beb0e 100644 --- a/app/views/administrate/application/edit.html.erb +++ b/app/views/administrate/application/edit.html.erb @@ -24,7 +24,7 @@ It displays a header, and renders the `_form` partial to do the heavy lifting. "Show #{page.page_title}", [namespace, page.resource], class: "button", - ) %> + ) if valid_action? :show %> diff --git a/app/views/administrate/application/index.html.erb b/app/views/administrate/application/index.html.erb index 9a9afa7ec3..8e402c6a5d 100644 --- a/app/views/administrate/application/index.html.erb +++ b/app/views/administrate/application/index.html.erb @@ -40,7 +40,7 @@ It renders the `_table` partial to display details about the resources. "New #{page.resource_name.titleize.downcase}", [:new, namespace, page.resource_name], class: "button", - ) %> + ) if valid_action? :new %> diff --git a/app/views/administrate/application/show.html.erb b/app/views/administrate/application/show.html.erb index b4e453b12f..b515a08d3b 100644 --- a/app/views/administrate/application/show.html.erb +++ b/app/views/administrate/application/show.html.erb @@ -25,7 +25,7 @@ as well as a link to its edit page. "Edit", [:edit, namespace, page.resource], class: "button", - ) %> + ) if valid_action? :edit %> diff --git a/app/views/fields/belongs_to/_index.html.erb b/app/views/fields/belongs_to/_index.html.erb index 86df398be2..005dba2b91 100644 --- a/app/views/fields/belongs_to/_index.html.erb +++ b/app/views/fields/belongs_to/_index.html.erb @@ -16,8 +16,12 @@ By default, the relationship is rendered as a link to the associated object. %> <% if field.data %> - <%= link_to( - field.display_associated_resource, - [namespace, field.data], - ) %> + <% if valid_action?(:show, field.attribute) %> + <%= link_to( + field.display_associated_resource, + [namespace, field.data], + ) %> + <% else %> + <%= field.display_associated_resource %> + <% end %> <% end %> diff --git a/app/views/fields/belongs_to/_show.html.erb b/app/views/fields/belongs_to/_show.html.erb index ca64897cfd..eeb0650f0b 100644 --- a/app/views/fields/belongs_to/_show.html.erb +++ b/app/views/fields/belongs_to/_show.html.erb @@ -16,8 +16,12 @@ By default, the relationship is rendered as a link to the associated object. %> <% if field.data %> - <%= link_to( - field.display_associated_resource, - [namespace, field.data], - ) %> + <% if valid_action?(:show, field.attribute) %> + <%= link_to( + field.display_associated_resource, + [namespace, field.data], + ) %> + <% else %> + <%= field.display_associated_resource %> + <% end %> <% end %> diff --git a/lib/administrate/namespace.rb b/lib/administrate/namespace.rb index 8b62b350ee..79ab2e7cc3 100644 --- a/lib/administrate/namespace.rb +++ b/lib/administrate/namespace.rb @@ -5,8 +5,14 @@ def initialize(namespace) end def resources - namespace_controller_paths.uniq.map do |controller| - controller.gsub(/^#{namespace}\//, "").to_sym + @resources ||= routes.map(&:first).uniq.map(&:to_sym) + end + + def routes + @routes ||= all_routes.select do |controller, _action| + controller.starts_with?(namespace.to_s) + end.map do |controller, action| + [controller.gsub(/^#{namespace}\//, ""), action] end end @@ -14,15 +20,9 @@ def resources attr_reader :namespace - def namespace_controller_paths - all_controller_paths.select do |controller| - controller.starts_with?(namespace.to_s) - end - end - - def all_controller_paths + def all_routes Rails.application.routes.routes.map do |route| - route.defaults[:controller].to_s + route.defaults.values_at(:controller, :action).map(&:to_s) end end end diff --git a/spec/example_app/app/controllers/admin/payments_controller.rb b/spec/example_app/app/controllers/admin/payments_controller.rb new file mode 100644 index 0000000000..901fdaae8c --- /dev/null +++ b/spec/example_app/app/controllers/admin/payments_controller.rb @@ -0,0 +1,4 @@ +module Admin + class PaymentsController < Admin::ApplicationController + end +end diff --git a/spec/example_app/app/dashboards/payment_dashboard.rb b/spec/example_app/app/dashboards/payment_dashboard.rb new file mode 100644 index 0000000000..b89d65f49e --- /dev/null +++ b/spec/example_app/app/dashboards/payment_dashboard.rb @@ -0,0 +1,16 @@ +require "administrate/base_dashboard" + +class PaymentDashboard < Administrate::BaseDashboard + ATTRIBUTE_TYPES = { + id: Field::Number, + created_at: Field::DateTime, + updated_at: Field::DateTime, + order: Field::BelongsTo, + } + + COLLECTION_ATTRIBUTES = [ + :id, + ] + + SHOW_PAGE_ATTRIBUTES = ATTRIBUTE_TYPES.keys +end diff --git a/spec/example_app/app/models/payment.rb b/spec/example_app/app/models/payment.rb new file mode 100644 index 0000000000..0079ac7ce8 --- /dev/null +++ b/spec/example_app/app/models/payment.rb @@ -0,0 +1,3 @@ +class Payment < ActiveRecord::Base + belongs_to :order +end diff --git a/spec/example_app/config/routes.rb b/spec/example_app/config/routes.rb index a32c26bdec..232d1dca20 100644 --- a/spec/example_app/config/routes.rb +++ b/spec/example_app/config/routes.rb @@ -4,6 +4,7 @@ resources :line_items resources :orders resources :products + resources :payments, only: [:index, :show] root to: "customers#index" end diff --git a/spec/example_app/db/migrate/20160815100728_create_payments.rb b/spec/example_app/db/migrate/20160815100728_create_payments.rb new file mode 100644 index 0000000000..e61b677ae6 --- /dev/null +++ b/spec/example_app/db/migrate/20160815100728_create_payments.rb @@ -0,0 +1,8 @@ +class CreatePayments < ActiveRecord::Migration + def change + create_table :payments do |t| + t.references :order, index: true + end + add_foreign_key :payments, :orders + end +end diff --git a/spec/example_app/db/schema.rb b/spec/example_app/db/schema.rb index 997fd815b3..2c3d3b8269 100644 --- a/spec/example_app/db/schema.rb +++ b/spec/example_app/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160119024340) do +ActiveRecord::Schema.define(version: 20160815100728) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -67,6 +67,12 @@ add_index "orders", ["customer_id"], name: "index_orders_on_customer_id", using: :btree + create_table "payments", force: :cascade do |t| + t.integer "order_id" + end + + add_index "payments", ["order_id"], name: "index_payments_on_order_id", using: :btree + create_table "products", force: :cascade do |t| t.string "name" t.float "price" @@ -82,4 +88,5 @@ add_foreign_key "line_items", "orders" add_foreign_key "line_items", "products" add_foreign_key "orders", "customers" + add_foreign_key "payments", "orders" end diff --git a/spec/factories.rb b/spec/factories.rb index 4c20c1e005..b7d7c38b8f 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -27,4 +27,8 @@ image_url \ "https://cdn.recombu.com/mobile/images/news/M11370/1264769196_w670.jpg" end + + factory :payment do + order + end end diff --git a/spec/features/orders_index_spec.rb b/spec/features/orders_index_spec.rb index 6544fde9b0..b300330d42 100644 --- a/spec/features/orders_index_spec.rb +++ b/spec/features/orders_index_spec.rb @@ -33,7 +33,7 @@ order = create(:order) visit admin_orders_path - click_on "Edit" + click_on t("administrate.actions.edit") expect(current_path).to eq(edit_admin_order_path(order)) end diff --git a/spec/features/orders_show_spec.rb b/spec/features/orders_show_spec.rb index aa1cb2ba04..58f6cb0fff 100644 --- a/spec/features/orders_show_spec.rb +++ b/spec/features/orders_show_spec.rb @@ -1,6 +1,6 @@ require "rails_helper" -feature "order index page" do +feature "order show page" do scenario "displays line item information" do line_item = create(:line_item) diff --git a/spec/features/payments_index_spec.rb b/spec/features/payments_index_spec.rb new file mode 100644 index 0000000000..4a038651de --- /dev/null +++ b/spec/features/payments_index_spec.rb @@ -0,0 +1,40 @@ +require "rails_helper" + +feature "payment index page" do + scenario "user views payment attributes" do + payment = create(:payment) + + visit admin_payments_path + + expect(page).to have_header("Payments") + expect(page).to have_content(payment.id) + end + + scenario "user clicks through to the payment show page", :js do + payment = create(:payment) + + visit admin_payments_path + click_row_for(payment) + + expect(page).to have_header(displayed(payment)) + end + + scenario "user cannot click through to the edit page" do + create(:payment) + + visit admin_payments_path + expect(page).not_to have_button t("administrate.actions.edit") + end + + scenario "user cannot click through to the new page" do + visit admin_payments_path + expect(page).not_to have_button "New payment" + end + + scenario "user cannot delete record" do + create(:payment) + + visit admin_payments_path + expect(page).not_to have_button t("administrate.actions.destroy") + end +end diff --git a/spec/features/payments_show_spec.rb b/spec/features/payments_show_spec.rb new file mode 100644 index 0000000000..8024a95549 --- /dev/null +++ b/spec/features/payments_show_spec.rb @@ -0,0 +1,17 @@ +require "rails_helper" + +feature "payment show page" do + scenario "user cannot click through to the edit page" do + payment = create(:payment) + + visit admin_payment_path(payment) + expect(page).not_to have_button t("administrate.actions.edit") + end + + scenario "user cannot delete record" do + payment = create(:payment) + + visit admin_payment_path(payment) + expect(page).not_to have_button t("administrate.actions.destroy") + end +end