Merge pull request #4310 from consul/refactor_cards_controllers

Refactor cards controllers
This commit is contained in:
Javi Martín
2021-01-14 17:34:01 +01:00
committed by GitHub
48 changed files with 230 additions and 249 deletions

View File

@@ -0,0 +1,7 @@
class Admin::Widget::Cards::RowComponent < ApplicationComponent
attr_reader :card
def initialize(card)
@card = card
end
end

View File

@@ -0,0 +1,22 @@
<% if cards.any? %>
<table>
<thead>
<tr>
<th><%= attribute_name(:title) %></th>
<th class="small-4"><%= attribute_name(:description) %></th>
<th><%= attribute_name(:link_text) %> / <%= attribute_name(:link_url) %></th>
<th><%= t("admin.shared.image") %></th>
<th><%= t("admin.shared.actions") %></th>
</tr>
</thead>
<tbody>
<% cards.each do |card| %>
<%= render Admin::Widget::Cards::RowComponent.new(card) %>
<% end %>
</tbody>
</table>
<% else %>
<div class="callout primary clear">
<%= no_cards_message %>
</div>
<% end %>

View File

@@ -0,0 +1,14 @@
class Admin::Widget::Cards::TableComponent < ApplicationComponent
attr_reader :cards, :no_cards_message
def initialize(cards, no_cards_message:)
@cards = cards
@no_cards_message = no_cards_message
end
private
def attribute_name(attribute)
::Widget::Card.human_attribute_name(attribute)
end
end

View File

@@ -9,11 +9,11 @@
</header>
</article>
<%= render Widgets::Feeds::ParticipationComponent.new(feeds) %>
<%= render Widget::Feeds::ParticipationComponent.new(feeds) %>
<% if processes_feed %>
<div class="feeds-list">
<%= render Widgets::Feeds::FeedComponent.new(processes_feed) %>
<%= render Widget::Feeds::FeedComponent.new(processes_feed) %>
</div>
<% end %>
</div>

View File

@@ -1,4 +1,4 @@
class Widgets::Feeds::DebateComponent < ApplicationComponent
class Widget::Feeds::DebateComponent < ApplicationComponent
attr_reader :debate
def initialize(debate)

View File

@@ -1,4 +1,4 @@
class Widgets::Feeds::FeedComponent < ApplicationComponent
class Widget::Feeds::FeedComponent < ApplicationComponent
attr_reader :feed
delegate :kind, to: :feed
@@ -15,11 +15,11 @@ class Widgets::Feeds::FeedComponent < ApplicationComponent
def item_component_class
case kind
when "proposals"
Widgets::Feeds::ProposalComponent
Widget::Feeds::ProposalComponent
when "debates"
Widgets::Feeds::DebateComponent
Widget::Feeds::DebateComponent
when "processes"
Widgets::Feeds::ProcessComponent
Widget::Feeds::ProcessComponent
end
end

View File

@@ -1,7 +1,7 @@
<div class="row margin-bottom feeds-list feeds-participation">
<% feeds.each do |feed| %>
<% if feed_proposals?(feed) || feed_debates?(feed) %>
<%= render Widgets::Feeds::FeedComponent.new(feed) %>
<%= render Widget::Feeds::FeedComponent.new(feed) %>
<% end %>
<% end %>
</div>

View File

@@ -1,4 +1,4 @@
class Widgets::Feeds::ParticipationComponent < ApplicationComponent
class Widget::Feeds::ParticipationComponent < ApplicationComponent
attr_reader :feeds
def initialize(feeds)

View File

@@ -1,4 +1,4 @@
class Widgets::Feeds::ProcessComponent < ApplicationComponent
class Widget::Feeds::ProcessComponent < ApplicationComponent
attr_reader :process
def initialize(process)

View File

@@ -1,4 +1,4 @@
class Widgets::Feeds::ProposalComponent < ApplicationComponent
class Widget::Feeds::ProposalComponent < ApplicationComponent
attr_reader :proposal
def initialize(proposal)

View File

@@ -1,9 +1,2 @@
class Admin::Dashboard::BaseController < Admin::BaseController
helper_method :namespace
private
def namespace
"admin"
end
end

View File

@@ -2,12 +2,4 @@ class Admin::Legislation::BaseController < Admin::BaseController
include FeatureFlags
feature_flag :legislation
helper_method :namespace
private
def namespace
"admin"
end
end

View File

@@ -1,9 +1,2 @@
class Admin::LocalCensusRecords::BaseController < Admin::BaseController
helper_method :namespace
private
def namespace
"admin"
end
end

View File

@@ -2,12 +2,4 @@ class Admin::Poll::BaseController < Admin::BaseController
include FeatureFlags
feature_flag :polls
helper_method :namespace
private
def namespace
"admin"
end
end

View File

@@ -1,9 +1,2 @@
class Admin::SiteCustomization::BaseController < Admin::BaseController
helper_method :namespace
private
def namespace
"admin"
end
end

View File

@@ -1,8 +1,15 @@
class Admin::SiteCustomization::CardsController < Admin::SiteCustomization::BaseController
skip_authorization_check
include Admin::Widget::CardsActions
load_and_authorize_resource :page, class: "::SiteCustomization::Page"
load_and_authorize_resource :card, through: :page, class: "Widget::Card"
helper_method :index_path
def index
@page = ::SiteCustomization::Page.find(params[:page_id])
@cards = @page.cards
end
private
def index_path
admin_site_customization_page_widget_cards_path(@page)
end
end

View File

@@ -1,74 +1,11 @@
class Admin::Widget::CardsController < Admin::BaseController
include Translatable
include ImageAttributes
def new
if header_card?
@card = ::Widget::Card.new(header: header_card?)
else
@card = ::Widget::Card.new(site_customization_page_id: params[:page_id])
end
end
def create
@card = ::Widget::Card.new(card_params)
if @card.save
redirect_to_customization_page_cards_or_homepage
else
render :new
end
end
def edit
@card = ::Widget::Card.find(params[:id])
end
def update
@card = ::Widget::Card.find(params[:id])
if @card.update(card_params)
redirect_to_customization_page_cards_or_homepage
else
render :edit
end
end
def destroy
@card = ::Widget::Card.find(params[:id])
@card.destroy!
redirect_to_customization_page_cards_or_homepage
end
include Admin::Widget::CardsActions
load_and_authorize_resource :card, class: "Widget::Card"
helper_method :index_path
private
def card_params
params.require(:widget_card).permit(
:link_url, :button_text, :button_url, :alignment, :header, :site_customization_page_id,
:columns,
translation_params(Widget::Card),
image_attributes: image_attributes
)
end
def header_card?
params[:header_card].present?
end
def redirect_to_customization_page_cards_or_homepage
notice = t("admin.site_customization.pages.cards.#{params[:action]}.notice")
if @card.site_customization_page_id
redirect_to admin_site_customization_page_cards_path(page), notice: notice
else
redirect_to admin_homepage_path, notice: notice
end
end
def page
::SiteCustomization::Page.find(@card.site_customization_page_id)
end
def resource
Widget::Card.find(params[:id])
def index_path
admin_homepage_path
end
end

View File

@@ -0,0 +1,59 @@
module Admin::Widget::CardsActions
extend ActiveSupport::Concern
include Translatable
include ImageAttributes
def new
@card.header = header_card?
render template: "#{cards_view_path}/new"
end
def create
if @card.save
redirect_to_index
else
render template: "#{cards_view_path}/new"
end
end
def edit
render template: "#{cards_view_path}/edit"
end
def update
if @card.update(card_params)
redirect_to_index
else
render template: "#{cards_view_path}/edit"
end
end
def destroy
@card.destroy!
redirect_to_index
end
private
def card_params
params.require(:widget_card).permit(
:link_url, :button_text, :button_url, :alignment, :header, :columns,
translation_params(Widget::Card),
image_attributes: image_attributes
)
end
def header_card?
params[:header_card].present?
end
def redirect_to_index
notice = t("admin.site_customization.pages.cards.#{params[:action]}.notice")
redirect_to index_path, notice: notice
end
def cards_view_path
"admin/widget/cards"
end
end

View File

@@ -3,8 +3,6 @@ class Officing::BallotSheetsController < Officing::BaseController
before_action :load_poll
before_action :load_officer_assignments, only: [:new, :create]
helper_method :namespace
def index
load_ballot_sheets
end
@@ -31,10 +29,6 @@ class Officing::BallotSheetsController < Officing::BaseController
private
def namespace
"officing"
end
def load_poll
@poll = Poll.find(params[:poll_id])
end

View File

@@ -88,6 +88,7 @@ module Abilities
can :manage, SiteCustomization::Page
can :manage, SiteCustomization::Image
can :manage, SiteCustomization::ContentBlock
can :manage, Widget::Card
can :access, :ckeditor
can :manage, Ckeditor::Picture

5
app/models/widget.rb Normal file
View File

@@ -0,0 +1,5 @@
module Widget
def self.table_name_prefix
"widget_"
end
end

View File

@@ -5,15 +5,14 @@ class Widget::Card < ApplicationRecord
foreign_key: "site_customization_page_id",
inverse_of: :cards
# table_name must be set before calls to 'translates'
self.table_name = "widget_cards"
translates :label, touch: true
translates :title, touch: true
translates :description, touch: true
translates :link_text, touch: true
include Globalizable
validates_translation :title, presence: true
def self.header
where(header: true)
end

View File

@@ -1,6 +1,4 @@
class Widget::Feed < ApplicationRecord
self.table_name = "widget_feeds"
KINDS = %w[proposals debates processes].freeze
def active?

View File

@@ -1,16 +0,0 @@
<table>
<thead>
<tr>
<th><%= t("admin.homepage.cards.title") %></th>
<th class="small-4"><%= t("admin.homepage.cards.description") %></th>
<th><%= t("admin.homepage.cards.link_text") %> / <%= t("admin.homepage.cards.link_url") %></th>
<th><%= t("admin.shared.image") %></th>
<th class="small-3"><%= t("admin.shared.actions") %></th>
</tr>
</thead>
<tbody>
<% cards.each do |card| %>
<%= render "card", card: card %>
<% end %>
</tbody>
</table>

View File

@@ -9,13 +9,10 @@
<%= link_to t("admin.homepage.create_header"), new_admin_widget_card_path(header_card: true), class: "button" %>
</div>
<% if @header.present? %>
<%= render "cards", cards: @header %>
<% else %>
<div class="callout primary clear">
<%= t("admin.homepage.no_header") %>
</div>
<% end %>
<%= render Admin::Widget::Cards::TableComponent.new(
@header,
no_cards_message: t("admin.homepage.no_header")
) %>
</div>
<hr>
@@ -27,13 +24,10 @@
<%= link_to t("admin.homepage.create_card"), new_admin_widget_card_path, class: "button" %>
</div>
<% if @cards.present? %>
<%= render "cards", cards: @cards %>
<% else %>
<div class="callout primary clear">
<%= t("admin.homepage.no_cards") %>
</div>
<% end %>
<%= render Admin::Widget::Cards::TableComponent.new(
@cards,
no_cards_message: t("admin.homepage.no_cards")
) %>
</div>
<hr>

View File

@@ -1,24 +0,0 @@
<tr id="<%= dom_id(card) %>" class="homepage-card">
<td>
<%= card.label %><br>
<%= card.title %>
</td>
<td><%= card.description %></td>
<td>
<%= card.link_text %><br>
<%= card.link_url %>
</td>
<!-- remove conditional once specs have image validations -->
<td>
<% if card.image.present? %>
<%= link_to t("admin.shared.show_image"), card.image_url(:large),
title: card.image.title, target: "_blank" %>
<% end %>
</td>
<td>
<%= render Admin::TableActionsComponent.new(card,
edit_path: edit_admin_widget_card_path(card, page_id: params[:page_id])
) %>
</td>
</tr>

View File

@@ -1,16 +0,0 @@
<table>
<thead>
<tr>
<th><%= t("admin.site_customization.pages.cards.title") %></th>
<th class="small-4"><%= t("admin.site_customization.pages.cards.description") %></th>
<th><%= t("admin.site_customization.pages.cards.link_text") %> / <%= t("admin.site_customization.pages.cards.link_url") %></th>
<th><%= t("admin.shared.image") %></th>
<th class="small-2"><%= t("admin.shared.actions") %></th>
</tr>
</thead>
<tbody>
<% cards.each do |card| %>
<%= render "card", card: card %>
<% end %>
</tbody>
</table>

View File

@@ -8,14 +8,11 @@
<div class="float-right">
<%= link_to t("admin.site_customization.pages.cards.create_card"),
new_admin_widget_card_path(page_id: params[:page_id]), class: "button" %>
new_admin_site_customization_page_widget_card_path(@page), class: "button" %>
</div>
<% if @cards.present? %>
<%= render "cards", cards: @cards %>
<% else %>
<div class="callout primary clear">
<%= t("admin.site_customization.pages.cards.no_cards") %>
</div>
<% end %>
<%= render Admin::Widget::Cards::TableComponent.new(
@cards,
no_cards_message: t("admin.site_customization.pages.cards.no_cards")
) %>
</div>

View File

@@ -30,7 +30,7 @@
<td>
<%= render Admin::TableActionsComponent.new(page) do |actions| %>
<%= actions.link_to t("admin.site_customization.pages.page.see_cards"),
admin_site_customization_page_cards_path(page),
admin_site_customization_page_widget_cards_path(page),
class: "cards-link" %>
<% if page.status == "published" %>

View File

@@ -1,6 +1,7 @@
<%= render "shared/globalize_locales", resource: @card %>
<%= translatable_form_for [:admin, @card] do |f| %>
<%= translatable_form_for [:admin, @page, @card] do |f| %>
<%= render "shared/errors", resource: @card %>
<div class="row">
<%= f.translatable_fields do |translations_form| %>
@@ -41,7 +42,6 @@
</div>
<%= f.hidden_field :header, value: @card.header? %>
<%= f.hidden_field :site_customization_page_id, value: @card.site_customization_page_id %>
<div class="row">
<div class="image-form">
<div class="image small-12 column">
@@ -49,7 +49,10 @@
</div>
</div>
<div class="column">
<%= f.submit(t("admin.homepage.#{action_name}.#{@card.header? ? "submit_header" : "submit_card"}"), class: "button success") %>
<%= f.submit(
t("admin.homepage.#{admin_submit_action(@card)}.#{@card.header? ? "submit_header" : "submit_card"}"),
class: "button success"
) %>
</div>
</div>
<% end %>

View File

@@ -1,3 +1,5 @@
<%= back_link_to index_path %>
<h2>
<% if @card.header? %>
<%= t("admin.homepage.edit.header_title") %>
@@ -6,4 +8,4 @@
<% end %>
</h2>
<%= render "form" %>
<%= render "admin/widget/cards/form" %>

View File

@@ -1,3 +1,5 @@
<%= back_link_to index_path %>
<h2>
<% if @card.header? %>
<%= t("admin.homepage.new.header_title") %>
@@ -6,4 +8,4 @@
<% end %>
</h2>
<%= render "form" %>
<%= render "admin/widget/cards/form" %>

View File

@@ -1 +1 @@
<%= render Widgets::Feeds::ParticipationComponent.new(@feeds) %>
<%= render Widget::Feeds::ParticipationComponent.new(@feeds) %>

View File

@@ -1,7 +1,7 @@
<div class="feeds-list">
<% @feeds.each do |feed| %>
<% if feed_processes?(feed) %>
<%= render Widgets::Feeds::FeedComponent.new(feed) %>
<%= render Widget::Feeds::FeedComponent.new(feed) %>
<% end %>
<% end %>
</div>

View File

@@ -1519,10 +1519,6 @@ en:
cards_title: cards
create_card: Create card
no_cards: There are no cards.
title: Title
description: Description
link_text: Link text
link_url: Link URL
columns_help: "Width of the card in number of columns. On mobile screens it's always a width of 100%."
create:
notice: "Card created successfully!"
@@ -1539,11 +1535,6 @@ en:
cards_title: Cards
create_card: Create card
no_cards: There are no cards.
cards:
title: Title
description: Description
link_text: Link text
link_url: Link URL
feeds:
proposals: Proposals
debates: Debates

View File

@@ -1518,10 +1518,6 @@ es:
cards_title: tarjetas
create_card: Crear tarjeta
no_cards: No hay tarjetas.
title: Título
description: Descripción
link_text: Texto del enlace
link_url: URL del enlace
columns_help: "Ancho de la tarjeta en número de columnas. En pantallas móviles siempre es un ancho del 100%."
create:
notice: "¡Tarjeta creada con éxito!"
@@ -1538,11 +1534,6 @@ es:
cards_title: Tarjetas
create_card: Crear tarjeta
no_cards: No hay tarjetas.
cards:
title: Título
description: Descripción
link_text: Texto del enlace
link_url: URL del enlace
feeds:
proposals: Propuestas
debates: Debates

View File

@@ -227,7 +227,7 @@ namespace :admin do
namespace :site_customization do
resources :pages, except: [:show] do
resources :cards, only: [:index]
resources :cards, except: [:show], as: :widget_cards
end
resources :images, only: [:index, :update, :destroy]
resources :content_blocks, except: [:show]
@@ -270,6 +270,10 @@ resolve "Audit" do |audit|
[*resource_hierarchy_for(audit.associated || audit.auditable), audit]
end
resolve "Widget::Card" do |card, options|
[*resource_hierarchy_for(card.page), card]
end
resolve "Budget::Group" do |group, options|
[group.budget, :group, options.merge(id: group)]
end

View File

@@ -1,9 +1,9 @@
require "rails_helper"
describe Widgets::Feeds::FeedComponent, type: :component do
describe Widget::Feeds::FeedComponent, type: :component do
it "renders a message when there are no items" do
feed = double(kind: "debates", items: [])
component = Widgets::Feeds::FeedComponent.new(feed)
component = Widget::Feeds::FeedComponent.new(feed)
render_inline component
@@ -15,7 +15,7 @@ describe Widgets::Feeds::FeedComponent, type: :component do
let(:feed) { Widget::Feed.new(kind: "debates") }
it "points to the debates path for homepage debates feeds" do
component = Widgets::Feeds::FeedComponent.new(feed)
component = Widget::Feeds::FeedComponent.new(feed)
render_inline component
@@ -23,7 +23,7 @@ describe Widgets::Feeds::FeedComponent, type: :component do
end
it "points to the debates filtered by goal for goal feeds" do
component = Widgets::Feeds::FeedComponent.new(SDG::Widget::Feed.new(feed, SDG::Goal[6]))
component = Widget::Feeds::FeedComponent.new(SDG::Widget::Feed.new(feed, SDG::Goal[6]))
render_inline component
@@ -35,7 +35,7 @@ describe Widgets::Feeds::FeedComponent, type: :component do
let(:feed) { Widget::Feed.new(kind: "proposals") }
it "points to the proposals path for homepage proposals feeds" do
component = Widgets::Feeds::FeedComponent.new(feed)
component = Widget::Feeds::FeedComponent.new(feed)
render_inline component
@@ -43,7 +43,7 @@ describe Widgets::Feeds::FeedComponent, type: :component do
end
it "points to the proposals filtered by goal for goal feeds" do
component = Widgets::Feeds::FeedComponent.new(SDG::Widget::Feed.new(feed, SDG::Goal[6]))
component = Widget::Feeds::FeedComponent.new(SDG::Widget::Feed.new(feed, SDG::Goal[6]))
render_inline component
@@ -55,7 +55,7 @@ describe Widgets::Feeds::FeedComponent, type: :component do
let(:feed) { Widget::Feed.new(kind: "processes") }
it "points to the legislation processes path for homepage processes feeds" do
component = Widgets::Feeds::FeedComponent.new(feed)
component = Widget::Feeds::FeedComponent.new(feed)
render_inline component
@@ -63,7 +63,7 @@ describe Widgets::Feeds::FeedComponent, type: :component do
end
it "points to the legislation processes path for goal processes feeds" do
component = Widgets::Feeds::FeedComponent.new(SDG::Widget::Feed.new(feed, SDG::Goal[6]))
component = Widget::Feeds::FeedComponent.new(SDG::Widget::Feed.new(feed, SDG::Goal[6]))
render_inline component

View File

@@ -112,4 +112,6 @@ describe Abilities::Administrator do
it { should be_able_to(:read, SDG::Manager) }
it { should be_able_to(:create, SDG::Manager) }
it { should be_able_to(:destroy, SDG::Manager) }
it { should be_able_to(:manage, Widget::Card) }
end

View File

@@ -9,6 +9,10 @@ describe Widget::Card do
it "is valid" do
expect(card).to be_valid
end
it "is not valid without a title" do
expect(build(:widget_card, title: "")).not_to be_valid
end
end
describe "#header" do

View File

@@ -164,6 +164,19 @@ describe "Polymorphic routes" do
expect(admin_polymorphic_path(shift)).to eq(admin_booth_shift_path(booth, shift))
end
it "routes widget cards" do
card = create(:widget_card)
expect(admin_polymorphic_path(card)).to eq(admin_widget_card_path(card))
end
it "routes site customization page widget cards" do
page = create(:site_customization_page)
card = create(:widget_card, page: page)
expect(admin_polymorphic_path(card)).to eq admin_site_customization_page_widget_card_path(page, card)
end
it "supports routes for actions like edit" do
proposal = create(:proposal)
milestone = create(:milestone, milestoneable: proposal)

View File

@@ -56,7 +56,7 @@ module Notifications
def error_message(resource_model = nil)
resource_model ||= "(.*)"
field_check_message = "Please check the marked fields to know how to correct them:"
/\d errors? prevented this #{resource_model} from being saved. #{field_check_message}/
/\d errors? prevented this #{resource_model} from being saved.(\n| )#{field_check_message}/
end
def fill_in_admin_notification_form(options = {})

View File

@@ -5,6 +5,8 @@ describe "Cards", :admin do
visit admin_homepage_path
click_link "Create card"
expect(page).to have_link("Go back", href: admin_homepage_path)
fill_in "Label (optional)", with: "Card label"
fill_in "Title", with: "Card text"
fill_in "Description", with: "Card description"
@@ -27,6 +29,15 @@ describe "Cards", :admin do
end
end
scenario "Create with errors", :js do
visit admin_homepage_path
click_link "Create card"
click_button "Create card"
expect(page).to have_text error_message
expect(page).to have_button "Create card"
end
scenario "Index" do
3.times { create(:widget_card) }
@@ -65,6 +76,8 @@ describe "Cards", :admin do
click_link "Edit"
end
expect(page).to have_link("Go back", href: admin_homepage_path)
within(".translatable-fields") do
fill_in "Label (optional)", with: "Card label updated"
fill_in "Title", with: "Card text updated"
@@ -130,6 +143,15 @@ describe "Cards", :admin do
end
end
scenario "Create with errors", :js do
visit admin_homepage_path
click_link "Create header"
click_button "Create header"
expect(page).to have_text error_message
expect(page).to have_button "Create header"
end
context "Page card" do
let!(:custom_page) { create(:site_customization_page, :published) }
@@ -142,10 +164,13 @@ describe "Cards", :admin do
click_link "Create card"
expect(page).to have_link("Go back",
href: admin_site_customization_page_widget_cards_path(custom_page))
fill_in "Title", with: "Card for a custom page"
click_button "Create card"
expect(page).to have_current_path admin_site_customization_page_cards_path(custom_page)
expect(page).to have_current_path admin_site_customization_page_widget_cards_path(custom_page)
expect(page).to have_content "Card for a custom page"
end
@@ -181,19 +206,22 @@ describe "Cards", :admin do
scenario "Edit", :js do
create(:widget_card, page: custom_page, title: "Original title")
visit admin_site_customization_page_cards_path(custom_page)
visit admin_site_customization_page_widget_cards_path(custom_page)
expect(page).to have_content("Original title")
click_link "Edit"
expect(page).to have_link("Go back",
href: admin_site_customization_page_widget_cards_path(custom_page))
within(".translatable-fields") do
fill_in "Title", with: "Updated title"
end
click_button "Save card"
expect(page).to have_current_path admin_site_customization_page_cards_path(custom_page)
expect(page).to have_current_path admin_site_customization_page_widget_cards_path(custom_page)
expect(page).to have_content "Updated title"
expect(page).not_to have_content "Original title"
end
@@ -201,7 +229,7 @@ describe "Cards", :admin do
scenario "Destroy", :js do
create(:widget_card, page: custom_page, title: "Card title")
visit admin_site_customization_page_cards_path(custom_page)
visit admin_site_customization_page_widget_cards_path(custom_page)
expect(page).to have_content("Card title")
@@ -209,7 +237,7 @@ describe "Cards", :admin do
click_link "Delete"
end
expect(page).to have_current_path admin_site_customization_page_cards_path(custom_page)
expect(page).to have_current_path admin_site_customization_page_widget_cards_path(custom_page)
expect(page).not_to have_content "Card title"
end
end