Merge pull request #865 from consul/trending-tags

Trending tags
This commit is contained in:
Enrique García
2016-01-27 15:50:38 +01:00
7 changed files with 241 additions and 37 deletions

View File

@@ -73,7 +73,7 @@ module CommentableActions
end
def tag_cloud
resource_model.last_week.tag_counts.order("#{resource_name.pluralize}_count": :desc, name: :asc).limit(5)
TagCloud.new(resource_model, params[:search])
end
def load_geozones

View File

@@ -3,26 +3,12 @@ module TagsHelper
def taggable_path(taggable_type, tag_name)
case taggable_type
when 'debate'
debates_path(tag: tag_name)
debates_path(search: tag_name)
when 'proposal'
proposals_path(tag: tag_name)
proposals_path(search: tag_name)
else
'#'
end
end
def taggable_counter_field(taggable_type)
"#{taggable_type.underscore.pluralize}_count"
end
def tag_cloud(tags, classes, counter_field = :taggings_count)
return [] if tags.empty?
max_count = tags.sort_by(&counter_field).last.send(counter_field).to_f
tags.each do |tag|
index = ((tag.send(counter_field) / max_count) * (classes.size - 1))
yield tag, classes[index.nan? ? 0 : index.round]
end
end
end

38
app/models/tag_cloud.rb Normal file
View File

@@ -0,0 +1,38 @@
class TagCloud
attr_accessor :resource_model, :scope
def initialize(resource_model, scope=nil)
@resource_model = resource_model
@scope = scope
end
def tags
resource_model_scoped.
last_week.tag_counts.
where("lower(name) NOT IN (?)", category_names + geozone_names + default_blacklist).
order("#{table_name}_count": :desc, name: :asc).
limit(10)
end
def category_names
ActsAsTaggableOn::Tag.where("kind = 'category'").map {|tag| tag.name.downcase }
end
def geozone_names
Geozone.all.map {|geozone| geozone.name.downcase }
end
def resource_model_scoped
scope && resource_model == Proposal ? resource_model.search(scope) : resource_model
end
def default_blacklist
['']
end
def table_name
resource_model.to_s.downcase.pluralize
end
end

View File

@@ -3,10 +3,9 @@
<h3 class="sidebar-title"><%= t("shared.tags_cloud.tags") %></h3>
<br>
<% tag_cloud @tag_cloud, %w[s m l] do |tag, css_class| %>
<%= link_to taggable_path(taggable, tag.name), class: css_class do %>
<%= tag.name %>
(<%= tag.send(taggable_counter_field(taggable)) %>)
<% @tag_cloud.tags.each do |tag| %>
<%= link_to taggable_path(taggable, tag.name) do %>
<span class="tag"><%= tag.name %></span>
<% end %>
<% end %>
</div>

View File

@@ -54,22 +54,6 @@ feature 'Tags' do
expect(page).to have_content "Hacienda"
end
scenario 'Tag Cloud' do
1.times { create(:debate, tag_list: 'Medio Ambiente') }
5.times { create(:debate, tag_list: 'Corrupción') }
5.times { create(:debate, tag_list: 'Educación') }
10.times { create(:debate, tag_list: 'Economía') }
visit debates_path
within(:css, "#tag-cloud") do
expect(page.find("a:eq(1)")).to have_content("Economía (10)")
expect(page.find("a:eq(2)")).to have_content("Corrupción (5)")
expect(page.find("a:eq(3)")).to have_content("Educación (5)")
expect(page.find("a:eq(4)")).to have_content("Medio Ambiente (1)")
end
end
scenario 'Create' do
user = create(:user)
login_as(user)
@@ -141,4 +125,81 @@ feature 'Tags' do
expect(page).to_not have_content 'Economía'
end
context 'Tag cloud' do
scenario 'Proposals' do
earth = create(:proposal, tag_list: 'Medio Ambiente')
money = create(:proposal, tag_list: 'Economía')
visit proposals_path
within "#tag-cloud" do
expect(page).to have_content "Medio Ambiente"
expect(page).to have_content "Economía"
end
end
scenario 'Debates' do
earth = create(:debate, tag_list: 'Medio Ambiente')
money = create(:debate, tag_list: 'Economía')
visit debates_path
within "#tag-cloud" do
expect(page).to have_content "Medio Ambiente"
expect(page).to have_content "Economía"
end
end
scenario "scoped by category" do
create(:tag, kind: 'category', name: 'Medio Ambiente')
create(:tag, kind: 'category', name: 'Economía')
earth = create(:proposal, tag_list: 'Medio Ambiente, Agua')
money = create(:proposal, tag_list: 'Economía, Corrupción')
visit proposals_path(search: 'Economía')
within "#tag-cloud" do
expect(page).to have_css(".tag", count: 1)
expect(page).to have_content "Corrupción"
expect(page).to_not have_content "Economía"
end
end
scenario "scoped by district" do
create(:geozone, name: 'Madrid')
create(:geozone, name: 'Barcelona')
earth = create(:proposal, tag_list: 'Madrid, Agua')
money = create(:proposal, tag_list: 'Barcelona, Playa')
visit proposals_path(search: 'Barcelona')
within "#tag-cloud" do
expect(page).to have_css(".tag", count: 1)
expect(page).to have_content "Playa"
expect(page).to_not have_content "Agua"
end
end
scenario "tag links" do
proposal1 = create(:proposal, tag_list: 'Medio Ambiente')
proposal2 = create(:proposal, tag_list: 'Medio Ambiente')
proposal3 = create(:proposal, tag_list: 'Economía')
visit proposals_path
within "#tag-cloud" do
click_link "Medio Ambiente"
end
expect(page).to have_css ".proposal", count: 2
expect(page).to have_content proposal1.title
expect(page).to have_content proposal2.title
expect(page).to_not have_content proposal3.title
end
end
end

View File

@@ -0,0 +1,116 @@
require 'rails_helper'
describe TagCloud do
describe "#tags" do
it "returns proposal tags" do
create(:proposal, tag_list: 'participation')
create(:debate, tag_list: 'world hunger')
tag_cloud = TagCloud.new(Proposal)
expect(tag_names(tag_cloud)).to contain_exactly('participation')
end
it "returns debate tags" do
create(:proposal, tag_list: 'participation')
create(:debate, tag_list: 'world hunger')
tag_cloud = TagCloud.new(Debate)
expect(tag_names(tag_cloud)).to contain_exactly('world hunger')
end
it "returns tags from last week" do
create(:proposal, tag_list: 'participation', created_at: 1.day.ago)
create(:proposal, tag_list: 'corruption', created_at: 2.weeks.ago)
tag_cloud = TagCloud.new(Proposal)
expect(tag_names(tag_cloud)).to contain_exactly('participation')
end
it "does not return category tags" do
create(:tag, kind: 'category', name: 'Education')
create(:tag, kind: 'category', name: 'Participation')
create(:proposal, tag_list: 'education, parks')
create(:proposal, tag_list: 'participation, water')
tag_cloud = TagCloud.new(Proposal)
expect(tag_names(tag_cloud)).to contain_exactly('parks', 'water')
end
it "does not return geozone names" do
create(:geozone, name: 'California')
create(:geozone, name: 'New York')
create(:proposal, tag_list: 'parks, California')
create(:proposal, tag_list: 'water, New York')
tag_cloud = TagCloud.new(Proposal)
expect(tag_names(tag_cloud)).to contain_exactly('parks', 'water')
end
it "returns tags scoped by category" do
create(:tag, kind: 'category', name: 'Education')
create(:tag, kind: 'category', name: 'Participation')
create(:proposal, tag_list: 'education, parks')
create(:proposal, tag_list: 'participation, water')
tag_cloud = TagCloud.new(Proposal, 'Education')
expect(tag_names(tag_cloud)).to contain_exactly('parks')
end
it "returns tags scoped by geozone" do
create(:geozone, name: 'California')
create(:geozone, name: 'New York')
create(:proposal, tag_list: 'parks, California')
create(:proposal, tag_list: 'water, New York')
tag_cloud = TagCloud.new(Proposal, 'California')
expect(tag_names(tag_cloud)).to contain_exactly('parks')
end
xit "returns tags scoped by category for debates"
xit "returns tags scoped by geozone for debates"
it "orders tags by count" do
3.times { create(:proposal, tag_list: 'participation') }
create(:proposal, tag_list: 'corruption')
tag_cloud = TagCloud.new(Proposal)
expect(tag_names(tag_cloud).first).to eq 'participation'
expect(tag_names(tag_cloud).second).to eq 'corruption'
end
it "orders tags by count and then by name" do
3.times { create(:proposal, tag_list: 'participation') }
3.times { create(:proposal, tag_list: 'health') }
create(:proposal, tag_list: 'corruption')
tag_cloud = TagCloud.new(Proposal)
expect(tag_names(tag_cloud).first).to eq 'health'
expect(tag_names(tag_cloud).second).to eq 'participation'
expect(tag_names(tag_cloud).third).to eq 'corruption'
end
it "returns a maximum of 10 tags" do
12.times { |i| create(:proposal, tag_list: "Tag #{i}") }
tag_cloud = TagCloud.new(Proposal)
expect(tag_names(tag_cloud).count).to eq(10)
end
end
end

View File

@@ -175,4 +175,8 @@ module CommonActions
create(:debate, :with_confidence_score, cached_votes_up: 80)]
end
def tag_names(tag_cloud)
tag_cloud.tags.map(&:name)
end
end