Refactor getting the public activity information

We had similar conditions many times and some duplication, particularly
between the code getting records and the code counting records. We can
remove it by returning a generic scope and calling the `count` method to
count the records and the `order` and `page` methods when we want to
pass the records to the view. And, since we only display one partial per
request, we can simplify the code to render all the partials. There's
one minor disadvantage to this approach: searching the code for the
place where these partials are rendered is now a bit harder since
searching the code for something like "render (.+) budget_investments"
won't return any results.

We're also writing conditions about a certain filter just once, by
setting `valid_filters`. This greatly simplifies the logic, although
again there's one minor disadvantage: we have to implement the
`current_filter` method, duplicating the logic already defined in the
`HasFilters` concern.
This commit is contained in:
Javi Martín
2021-09-03 21:15:10 +02:00
parent 62b23f1e56
commit 64258baf97
3 changed files with 48 additions and 63 deletions

View File

@@ -1,33 +1,30 @@
<% load_filtered_activity if valid_access? %>
<% if valid_access? %> <% if valid_access? %>
<% if valid_filters.any? %>
<ul class="menu simple margin-top"> <ul class="menu simple margin-top">
<% valid_filters.each do |filter| %> <% valid_filters.each do |filter| %>
<% if @activity_counts[filter] > 0 %>
<% if current_filter == filter %> <% if current_filter == filter %>
<li class="is-active"> <li class="is-active">
<h2><%= t("users.show.filters.#{filter}", count: @activity_counts[filter]) %></h2> <h2><%= t("users.show.filters.#{filter}", count: count(filter)) %></h2>
</li> </li>
<% else %> <% else %>
<li> <li>
<%= link_to t("users.show.filters.#{filter}", count: @activity_counts[filter]), <%= link_to t("users.show.filters.#{filter}", count: count(filter)),
current_path_with_query_params(filter: filter, page: 1) %> current_path_with_query_params(filter: filter, page: 1) %>
</li> </li>
<% end %> <% end %>
<% end %> <% end %>
<% end %>
</ul> </ul>
<% if @activity_counts.values.inject(&:+) == 0 %> <% if current_filter == "follows" %>
<%= render "users/following", user: user, follows: follows.group_by(&:followable_type) %>
<% else %>
<%= render_user_partial current_filter %>
<% end %>
<% else %>
<div class="callout primary"> <div class="callout primary">
<%= t("users.show.no_activity") %> <%= t("users.show.no_activity") %>
</div> </div>
<% end %> <% end %>
<%= render "users/following", user: user, follows: @follows if @follows.present? %>
<%= render "users/proposals", proposals: @proposals if @proposals.present? && feature?(:proposals) %>
<%= render "users/debates", debates: @debates if @debates.present? && feature?(:debates) %>
<%= render "users/budget_investments", budget_investments: @budget_investments if @budget_investments.present? && feature?(:budgets) %>
<%= render "users/comments", comments: @comments if @comments.present? %>
<% else %> <% else %>
<div class="callout warning margin"> <div class="callout warning margin">
<%= t("users.show.private_activity") %> <%= t("users.show.private_activity") %>

View File

@@ -1,6 +1,6 @@
class Users::PublicActivityComponent < ApplicationComponent class Users::PublicActivityComponent < ApplicationComponent
attr_reader :user attr_reader :user
delegate :authorized_current_user?, :current_path_with_query_params, :valid_filters, :current_filter, to: :helpers delegate :authorized_current_user?, :current_path_with_query_params, to: :helpers
def initialize(user) def initialize(user)
@user = user @user = user
@@ -10,66 +10,56 @@ class Users::PublicActivityComponent < ApplicationComponent
user.public_activity || authorized_current_user? user.public_activity || authorized_current_user?
end end
def current_filter
if valid_filters.include?(params[:filter])
params[:filter]
else
valid_filters.first
end
end
def valid_filters
@valid_filters ||= [
("proposals" if feature?(:proposals)),
("debates" if feature?(:debates)),
("budget_investments" if feature?(:budgets)),
"comments",
"follows"
].compact.select { |filter| send(filter).any? }
end
private private
def set_activity_counts def proposals
@activity_counts = ActiveSupport::HashWithIndifferentAccess.new( Proposal.where(author_id: user.id)
proposals: Proposal.where(author_id: @user.id).count,
debates: (Setting["process.debates"] ? Debate.where(author_id: @user.id).count : 0),
budget_investments: (Setting["process.budgets"] ? Budget::Investment.where(author_id: @user.id).count : 0),
comments: only_active_commentables.count,
follows: @user.follows.map(&:followable).compact.count)
end end
def load_filtered_activity def debates
set_activity_counts Debate.where(author_id: user.id)
case params[:filter]
when "proposals" then load_proposals
when "debates" then load_debates
when "budget_investments" then load_budget_investments
when "comments" then load_comments
when "follows" then load_follows
else load_available_activity
end
end end
def load_available_activity def comments
if @activity_counts[:proposals] > 0 only_active_commentables.includes(:commentable)
load_proposals
@current_filter = "proposals"
elsif @activity_counts[:debates] > 0
load_debates
@current_filter = "debates"
elsif @activity_counts[:budget_investments] > 0
load_budget_investments
@current_filter = "budget_investments"
elsif @activity_counts[:comments] > 0
load_comments
@current_filter = "comments"
elsif @activity_counts[:follows] > 0
load_follows
@current_filter = "follows"
end
end end
def load_proposals def budget_investments
@proposals = Proposal.created_by(@user).order(created_at: :desc).page(params[:page]) Budget::Investment.where(author_id: user.id)
end end
def load_debates def follows
@debates = Debate.where(author_id: @user.id).order(created_at: :desc).page(params[:page]) @follows ||= user.follows.select { |follow| follow.followable.present? }
end end
def load_comments def count(filter)
@comments = only_active_commentables.includes(:commentable).order(created_at: :desc).page(params[:page]) send(filter).count
end end
def load_budget_investments def render_user_partial(filter)
@budget_investments = Budget::Investment.where(author_id: @user.id).order(created_at: :desc).page(params[:page]) render "users/#{filter}", "#{filter}": send(filter).order(created_at: :desc).page(page)
end end
def load_follows def page
@follows = @user.follows.group_by(&:followable_type) params[:page]
end end
def only_active_commentables def only_active_commentables
@@ -84,6 +74,6 @@ class Users::PublicActivityComponent < ApplicationComponent
end end
def all_user_comments def all_user_comments
Comment.not_valuations.not_as_admin_or_moderator.where(user_id: @user.id) Comment.not_valuations.not_as_admin_or_moderator.where(user_id: user.id)
end end
end end

View File

@@ -1,6 +1,4 @@
class UsersController < ApplicationController class UsersController < ApplicationController
has_filters %w[proposals debates budget_investments comments follows], only: :show
load_and_authorize_resource load_and_authorize_resource
helper_method :valid_interests_access? helper_method :valid_interests_access?
helper_method :authorized_current_user? helper_method :authorized_current_user?