This fixes issue #2298.
Following a hashtag with a dot now no longer breaks the user's stream page. All unacceptable hashtag chars are stripped out, and the given tag is normalized before being followed.
This commit is contained in:
parent
e885e8492f
commit
78a96a18e4
4 changed files with 75 additions and 15 deletions
|
|
@ -14,13 +14,14 @@ class TagFollowingsController < ApplicationController
|
||||||
# POST /tag_followings
|
# POST /tag_followings
|
||||||
# POST /tag_followings.xml
|
# POST /tag_followings.xml
|
||||||
def create
|
def create
|
||||||
@tag = ActsAsTaggableOn::Tag.find_or_create_by_name(tag_name)
|
name_normalized = ActsAsTaggableOn::Tag.normalize( params['name'] )
|
||||||
|
@tag = ActsAsTaggableOn::Tag.find_or_create_by_name(name_normalized)
|
||||||
@tag_following = current_user.tag_followings.new(:tag_id => @tag.id)
|
@tag_following = current_user.tag_followings.new(:tag_id => @tag.id)
|
||||||
|
|
||||||
if @tag_following.save
|
if @tag_following.save
|
||||||
flash[:notice] = I18n.t('tag_followings.create.success', :name => tag_name)
|
flash[:notice] = I18n.t('tag_followings.create.success', :name => name_normalized)
|
||||||
else
|
else
|
||||||
flash[:error] = I18n.t('tag_followings.create.failure', :name => tag_name)
|
flash[:error] = I18n.t('tag_followings.create.failure', :name => name_normalized)
|
||||||
end
|
end
|
||||||
|
|
||||||
redirect_to :back
|
redirect_to :back
|
||||||
|
|
@ -53,19 +54,12 @@ class TagFollowingsController < ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_multiple
|
def create_multiple
|
||||||
tags = params[:tags].split(",")
|
params[:tags].split(",").each do |name|
|
||||||
tags.each do |tag|
|
name_normalized = ActsAsTaggableOn::Tag.normalize(name)
|
||||||
tag_name = tag.gsub(/^#/,"")
|
@tag = ActsAsTaggableOn::Tag.find_or_create_by_name(name_normalized)
|
||||||
|
|
||||||
@tag = ActsAsTaggableOn::Tag.find_or_create_by_name(tag_name)
|
|
||||||
@tag_following = current_user.tag_followings.create(:tag_id => @tag.id)
|
@tag_following = current_user.tag_followings.create(:tag_id => @tag.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
redirect_to multi_path
|
redirect_to multi_path
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
|
||||||
def tag_name
|
|
||||||
@tag_name ||= params[:name].gsub(/\s/,'') if params[:name]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
class ActsAsTaggableOn::Tag
|
class ActsAsTaggableOn::Tag
|
||||||
def followed_count
|
def followed_count
|
||||||
@followed_count ||= TagFollowing.where(:tag_id => self.id).count
|
@followed_count ||= TagFollowing.where(:tag_id => self.id).count
|
||||||
end
|
end
|
||||||
|
|
@ -6,4 +6,13 @@ class ActsAsTaggableOn::Tag
|
||||||
def self.autocomplete(name)
|
def self.autocomplete(name)
|
||||||
where("name LIKE ?", "#{name.downcase}%")
|
where("name LIKE ?", "#{name.downcase}%")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.normalize(name)
|
||||||
|
if name =~ /^#?<3/
|
||||||
|
# Special case for love, because the world needs more love.
|
||||||
|
'<3'
|
||||||
|
elsif name
|
||||||
|
name.gsub(/[^\w-]/, '')
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,40 @@ describe TagFollowingsController do
|
||||||
post :create, :name => "SOMESTUFF"
|
post :create, :name => "SOMESTUFF"
|
||||||
assigns[:tag].name.should == "somestuff"
|
assigns[:tag].name.should == "somestuff"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'strips invalid characters from the tag name' do
|
||||||
|
{
|
||||||
|
'node.js' => 'nodejs',
|
||||||
|
'#unneeded-hash' => 'unneeded-hash',
|
||||||
|
'hash#inside' => 'hashinside',
|
||||||
|
'.dotatstart' => 'dotatstart',
|
||||||
|
'f!u@n#k$y%-c^h&a*r(a)c{t}e[r]s' => 'funky-characters',
|
||||||
|
'how about spaces' => 'howaboutspaces',
|
||||||
|
}.each do |invalid, normalized|
|
||||||
|
ActsAsTaggableOn::Tag.find_by_name(invalid).should be_nil
|
||||||
|
ActsAsTaggableOn::Tag.find_by_name(normalized).should be_nil
|
||||||
|
|
||||||
|
post :create, :name => invalid
|
||||||
|
|
||||||
|
ActsAsTaggableOn::Tag.find_by_name(invalid).should be_nil
|
||||||
|
ActsAsTaggableOn::Tag.find_by_name(normalized).should_not be_nil, "Expected #{normalized.inspect} not to be nil"
|
||||||
|
bob.reload
|
||||||
|
bob.followed_tags.map(&:name).should include(normalized)
|
||||||
|
bob.followed_tags.map(&:name).should_not include(invalid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'follows love' do
|
||||||
|
name = '<3'
|
||||||
|
|
||||||
|
ActsAsTaggableOn::Tag.find_by_name(name).should be_nil
|
||||||
|
|
||||||
|
post :create, :name => name
|
||||||
|
|
||||||
|
ActsAsTaggableOn::Tag.find_by_name(name).should_not be_nil
|
||||||
|
bob.reload
|
||||||
|
bob.followed_tags.map(&:name).should include(name)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'fails to' do
|
describe 'fails to' do
|
||||||
|
|
@ -147,6 +181,28 @@ describe TagFollowingsController do
|
||||||
|
|
||||||
response.should be_redirect
|
response.should be_redirect
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'strips invalid characters from the tag name' do
|
||||||
|
{
|
||||||
|
'node.js' => 'nodejs',
|
||||||
|
'#unneeded-hash' => 'unneeded-hash',
|
||||||
|
'hash#inside' => 'hashinside',
|
||||||
|
'.dotatstart' => 'dotatstart',
|
||||||
|
'f!u@n#k$y%-c^h&a*r(a)c{t}e[r]s' => 'funky-characters',
|
||||||
|
'how about spaces' => 'howaboutspaces',
|
||||||
|
}.each do |invalid, normalized|
|
||||||
|
ActsAsTaggableOn::Tag.find_by_name(invalid).should be_nil
|
||||||
|
ActsAsTaggableOn::Tag.find_by_name(normalized).should be_nil
|
||||||
|
|
||||||
|
post :create_multiple, :tags => invalid
|
||||||
|
|
||||||
|
ActsAsTaggableOn::Tag.find_by_name(invalid).should be_nil
|
||||||
|
ActsAsTaggableOn::Tag.find_by_name(normalized).should_not be_nil
|
||||||
|
bob.reload
|
||||||
|
bob.followed_tags.map(&:name).should include(normalized)
|
||||||
|
bob.followed_tags.map(&:name).should_not include(invalid)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ class SpecDoc
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_content?(string)
|
def has_content?(string)
|
||||||
@html.xpath("//*[contains(text(), '#{string}')]").any?
|
escaped = string.gsub("'", "\\'")
|
||||||
|
@html.xpath("//*[contains(text(), '#{escaped}')]").any?
|
||||||
end
|
end
|
||||||
def has_no_content?(string)
|
def has_no_content?(string)
|
||||||
! has_content?(string)
|
! has_content?(string)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue