Skip to content

Commit

Permalink
Remove duplication in poll actions tables
Browse files Browse the repository at this point in the history
We were using the same logic in four different places, so we're creating
a new class to handle that logic.

Note that I didn't find a way to delegate the `content` method to a
`Admin::TableActionsComponent`, so we're delegating the `action` method
instead. That means we need to create a method returning an
`Admin::TableActionsComponent`. We also need to cache this object;
otherwise we were getting an error when calling `actions.action` from
the `Admin::Poll::Questions::TableActionsComponent`.
  • Loading branch information
javierm committed Sep 20, 2022
1 parent 7e465fd commit bcd4970
Show file tree
Hide file tree
Showing 11 changed files with 91 additions and 40 deletions.
3 changes: 3 additions & 0 deletions app/components/admin/allowed_table_actions_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<%= render table_actions_component do %>
<%= content %>
<% end %>
20 changes: 20 additions & 0 deletions app/components/admin/allowed_table_actions_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class Admin::AllowedTableActionsComponent < ApplicationComponent
attr_reader :record, :options
delegate :can?, to: :helpers
delegate :action, to: :table_actions_component

def initialize(record, **options)
@record = record
@options = options
end

private

def actions
(options[:actions] || [:edit, :destroy]).select { |action| can?(action, record) }
end

def table_actions_component
@table_actions_component ||= Admin::TableActionsComponent.new(record, **options.merge(actions: actions))
end
end
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
<%= render Admin::TableActionsComponent.new(document,
actions: actions,
destroy_path: document_path(document)) do |table_actions| %>
<%= table_actions.action(:download,
text: t("documents.buttons.download_document"),
path: document.attachment,
target: "_blank",
rel: "nofollow") %>
<%= render Admin::AllowedTableActionsComponent.new(document,
destroy_path: document_path(document)) do |actions| %>
<%= actions.action(:download,
text: t("documents.buttons.download_document"),
path: document.attachment,
target: "_blank",
rel: "nofollow") %>
<% end %>
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
class Admin::Poll::Questions::Answers::Documents::TableActionsComponent < ApplicationComponent
attr_reader :document
delegate :can?, to: :helpers

def initialize(document)
@document = document
end

private

def actions
[:destroy].select { |action| can?(action, document) }
end
end
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<%= render Admin::TableActionsComponent.new(answer, actions: actions) %>
<%= render Admin::AllowedTableActionsComponent.new(answer) %>
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
class Admin::Poll::Questions::Answers::TableActionsComponent < ApplicationComponent
attr_reader :answer
delegate :can?, to: :helpers

def initialize(answer)
@answer = answer
end

private

def actions
[:edit, :destroy].select { |action| can?(action, answer) }
end
end
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<%= render Admin::TableActionsComponent.new(video, actions: actions) %>
<%= render Admin::AllowedTableActionsComponent.new(video) %>
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
class Admin::Poll::Questions::Answers::Videos::TableActionsComponent < ApplicationComponent
attr_reader :video
delegate :can?, to: :helpers

def initialize(video)
@video = video
end

private

def actions
[:edit, :destroy].select { |action| can?(action, video) }
end
end
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<%= render Admin::TableActionsComponent.new(question, actions: actions) do |table_actions| %>
<%= table_actions.action(:answers, text: t("admin.polls.show.edit_answers")) %>
<%= render Admin::AllowedTableActionsComponent.new(question) do |actions| %>
<%= actions.action(:answers, text: t("admin.polls.show.edit_answers")) %>
<% end %>
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
class Admin::Poll::Questions::TableActionsComponent < ApplicationComponent
attr_reader :question
delegate :can?, to: :helpers

def initialize(question)
@question = question
end

private

def actions
[:edit, :destroy].select { |action| can?(action, question) }
end
end
57 changes: 57 additions & 0 deletions spec/components/admin/allowed_table_actions_component_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
require "rails_helper"

describe Admin::AllowedTableActionsComponent, controller: Admin::BaseController do
before do
sign_in(create(:administrator).user)
allow_any_instance_of(Admin::AllowedTableActionsComponent).to receive(:can?).and_return true
end
let(:record) { create(:banner, title: "Important!") }

it "renders edit and destroy actions by default if they're allowed" do
component = Admin::AllowedTableActionsComponent.new(record)

render_inline component

expect(page).to have_link count: 1
expect(page).to have_link "Edit"
expect(page).to have_button count: 1
expect(page).to have_button "Delete"
end

it "accepts an actions parameter" do
render_inline Admin::AllowedTableActionsComponent.new(record, actions: [:edit])

expect(page).to have_link "Edit"
expect(page).not_to have_button "Delete"
end

it "accepts custom options" do
render_inline Admin::AllowedTableActionsComponent.new(record, edit_text: "change", edit_path: "/myedit")

expect(page).to have_link "change", href: "/myedit"
end

it "accepts custom content" do
render_inline Admin::AllowedTableActionsComponent.new(record) do
"<a href='/'>Main</a>".html_safe
end

expect(page).to have_link count: 2
expect(page).to have_link "Main", href: "/"
expect(page).to have_link "Edit"

expect(page).to have_button count: 1
expect(page).to have_button "Delete"
end

it "only renders the allowed actions" do
component = Admin::AllowedTableActionsComponent.new(record)
allow(component).to receive(:can?).with(:edit, record).and_return true
allow(component).to receive(:can?).with(:destroy, record).and_return false

render_inline component

expect(page).to have_link "Edit"
expect(page).not_to have_button "Delete"
end
end

0 comments on commit bcd4970

Please sign in to comment.