Skip to content

Commit

Permalink
πŸžπŸ”¨ Journal: Entry body supports multiple overlapping Keywords
Browse files Browse the repository at this point in the history
- #1714

Turns out, it was a renderer-layer thing; where the shorter `Keyword`
was getting linkfied prior to the longer `Keyword`, and when I switched
to linkify the longer `Keyword` first it would double-down on the links
putting a link to the shorter keyword within the longer one!

So now I'm matching the `#` as part of the `Keyword`, and replacing it
with the html entity for `#`, (aka `#`)

This makes it so when we linkify keywords long-to-short; the longer
keywords no longer contain the shorter keyword; eliminating the nested
`a` tags.
  • Loading branch information
zspencer committed Jul 27, 2023
1 parent 6451f8e commit cca9c82
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 5 deletions.
8 changes: 4 additions & 4 deletions app/furniture/journal/entry_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def body_html
end

private def postprocess(text)
entry.keywords.map do |keyword|
entry.keywords.by_length.map do |keyword|
linkify_keyword(text, keyword)
end

Expand All @@ -22,13 +22,13 @@ def body_html

private def linkify_keyword(text, keyword)
text.gsub!(keywords_regex(keyword)) do |match|
link_to(match, keyword.location)
link_to(match.gsub("#", "#").html_safe, keyword.location) # rubocop:disable Rails/OutputSafety
end
end

# We sort the keywords longest to shortest because regex matches groups left-to-right
# We sort the variants longest to shortest because regex matches groups left-to-right
private def keywords_regex(keyword)
/\#(#{keyword.canonical_with_aliases.sort.reverse.join("|")})/i
/(\##{keyword.canonical_with_aliases.sort.join("|")})/i
end

private def published_at
Expand Down
2 changes: 2 additions & 0 deletions app/furniture/journal/keyword.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class Keyword < ApplicationRecord
validates :canonical_keyword, presence: true, uniqueness: {case_sensitive: false, scope: :journal_id}
belongs_to :journal, inverse_of: :keywords

scope(:by_length, -> { order("LENGTH(canonical_keyword) DESC") })

scope(:search, lambda do |*keywords|
where("lower(aliases::text)::text[] && ARRAY[?]::text[]", keywords.map(&:downcase))
.or(where("lower(canonical_keyword) IN (?)", keywords.map(&:downcase)))
Expand Down
4 changes: 3 additions & 1 deletion spec/furniture/journal/entry_component_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
subject(:output) { render_inline(component) }

let(:component) { described_class.new(entry: entry) }
let(:entry) { create(:journal_entry, body: "https://www.google.com @[email protected] #GoodTimes") }
let(:entry) { create(:journal_entry, body: "https://www.google.com @[email protected] #GoodTimes with the #GoodTimesBand") }

it { is_expected.to have_link("https://www.google.com", href: "https://www.google.com") }
it { is_expected.to have_link("#GoodTimes", href: polymorphic_path(entry.journal.keywords.find_by(canonical_keyword: "GoodTimes").location)) }

it { is_expected.to have_link("#GoodTimesBand", href: polymorphic_path(entry.journal.keywords.find_by(canonical_keyword: "GoodTimesBand").location)) }
end
23 changes: 23 additions & 0 deletions spec/furniture/journal/keyword_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@
it { is_expected.to validate_uniqueness_of(:canonical_keyword).case_insensitive.scoped_to(:journal_id) }
it { is_expected.to belong_to(:journal).inverse_of(:keywords) }

describe ".by_length" do
it "orders the results by the length of their canonical keyword" do
journal = create(:journal)
create_list(:journal_keyword, 5, journal: journal)
results = described_class.by_length
expect(results[0].canonical_keyword.length).to be >= results[1].canonical_keyword.length
expect(results[1].canonical_keyword.length).to be >= results[2].canonical_keyword.length
expect(results[2].canonical_keyword.length).to be >= results[3].canonical_keyword.length
expect(results[3].canonical_keyword.length).to be >= results[4].canonical_keyword.length
end
end

describe ".extract_and_create_from!" do
it "doesn't skip longer versions" do
journal = create(:journal)
journal.keywords.extract_and_create_from!("#SarinsGarden is a large #WorldGarden on the planet #Sarin.")

expect(described_class).to exist(canonical_keyword: "SarinsGarden", journal: journal)
expect(described_class).to exist(canonical_keyword: "WorldGarden", journal: journal)
expect(described_class).to exist(canonical_keyword: "Sarin", journal: journal)
end
end

describe ".search" do
it "returns the `Keywords` that match either canonicaly or via aliases" do
dog = create(:journal_keyword, canonical_keyword: "Dog", aliases: ["doggo"])
Expand Down

0 comments on commit cca9c82

Please sign in to comment.