рельсы:получите тизер / выдержку к статье
-
22-08-2019 - |
Вопрос
У меня есть страница, на которой будут перечислены новостные статьи.Чтобы сократить длину страницы, я хочу отобразить только тизер (первые 200 слов / 600 букв статьи), а затем отобразить ссылку "подробнее ...", при нажатии на которую остальная часть статьи будет расширена с помощью jQuery / Javascript.Теперь я со всем этим разобрался и даже нашел следующий вспомогательный метод на какой-нибудь странице вставки, который гарантирует, что новостная статья (строка) не будет разорвана прямо посреди слова:
def shorten (string, count = 30)
if string.length >= count
shortened = string[0, count]
splitted = shortened.split(/\s/)
words = splitted.length
splitted[0, words-1].join(" ") + ' ...'
else
string
end
end
Проблема, с которой я сталкиваюсь, заключается в том, что тела новостных статей, которые я получаю из базы данных, имеют формат HTML.Так что, если мне не повезет, вышеупомянутый помощник разорвет строку моей статьи прямо в середине html-тега и вставит туда строку "подробнее ..." (напримермежду ""), что приведет к повреждению моего html-кода на странице.
Есть ли какой-нибудь способ обойти это или есть плагин, который я могу использовать для генерации выдержек / тизеров из HTML-строки?
Решение 3
Большое спасибо за ваши ответы!Однако, тем временем я наткнулся на Плагин для усечения jQuery HTML, что идеально соответствует моим целям и переносит усечение на сторону клиента.Легче от этого не становится :-)
Другие советы
Вы можете использовать комбинацию Дезинфицировать и Усекать.
truncate("And they found that many people were sleeping better.",
:omission => "... (continued)", :length => 15)
# => And they found... (continued)
Я выполняю аналогичную задачу, где у меня есть записи в блоге, и я просто хочу показать краткий отрывок.Так что, на мой взгляд, я просто делаю:
sanitize(truncate(blog_post.body, length: 150))
Это удаляет HTML-теги, выдает мне первые 150 символов и обрабатывается в представлении, так что это удобно для MVC.
Удачи вам!
Мой ответ здесь должен выполнять работу.Первоначальный вопрос (ошибка, заданный мной) был об усечении markdown, но в итоге я преобразовал markdown в HTML, а затем обрезал его, так что это должно сработать.
Конечно, если ваш сайт получает много трафика, вам следует кэшировать отрывок (возможно, при создании / обновлении публикации вы могли бы сохранить отрывок в базе данных?), это также означало бы, что вы могли бы разрешить пользователю изменять или вводить свой собственный отрывок
Использование:
>> puts "<p><b><a href=\"hi\">Something</a></p>".truncate_html(5, at_end = "...")
=> <p><b><a href="hi">Someth...</a></b></p>
..и код (скопированный из другого ответа):
require 'rexml/parsers/pullparser'
class String
def truncate_html(len = 30, at_end = nil)
p = REXML::Parsers::PullParser.new(self)
tags = []
new_len = len
results = ''
while p.has_next? && new_len > 0
p_e = p.pull
case p_e.event_type
when :start_element
tags.push p_e[0]
results << "<#{tags.last}#{attrs_to_s(p_e[1])}>"
when :end_element
results << "</#{tags.pop}>"
when :text
results << p_e[0][0..new_len]
new_len -= p_e[0].length
else
results << "<!-- #{p_e.inspect} -->"
end
end
if at_end
results << "..."
end
tags.reverse.each do |tag|
results << "</#{tag}>"
end
results
end
private
def attrs_to_s(attrs)
if attrs.empty?
''
else
' ' + attrs.to_a.map { |attr| %{#{attr[0]}="#{attr[1]}"} }.join(' ')
end
end
end
вам пришлось бы написать более сложные парсеры, если вы не хотите разделять html-элементы посередине.он должен был бы помнить, находится ли он в середине <> блокировать, и если это между двумя тегами.
даже если бы вы сделали это, у вас все равно возникли бы проблемы.если кто-то поместит всю статью в html-элемент, поскольку анализатор не смог ее нигде разделить из-за отсутствия закрывающего тега.
если это вообще возможно, я бы постарался не вставлять никаких тегов в статьи или сохранить их для тегов, которые ничего не содержат (нет <div>
и так далее).таким образом, вам нужно будет только проверить, находитесь ли вы в середине тега, что довольно просто:
def shorten (string, count = 30)
if string.length >= count
shortened = string[0, count]
splitted = shortened.split(/\s/)
words = splitted.length
if(splitted[words-1].include? "<")
splitted[0,words-2].join(" ") + ' ...'
else
splitted[0, words-1].join(" ") + ' ...'
else
string
end
end
Я бы очистил HTML-код и извлек первое предложение.Предполагая, что у вас есть модель статьи с атрибутом 'body', который содержит HTML:
# lib/core_ext/string.rb
class String
def first_sentence
self[/(\A[^.|!|?]+)/, 1]
end
end
# app/models/article.rb
def teaser
HTML::FullSanitizer.new.sanitize(body).first_sentence
end
Это превратило бы "<b>Это</b> <em>важная</em> статья!И вот остальная часть статьи". в "Это важная статья".
Я решил это, используя следующее решение
Установите gem "дезинфицировать"
gem install sanitize
и использовал следующий код, здесь Тело это текст, содержащий html-теги.
<%= content_tag :div, Sanitize.clean(truncate(body, length: 200, separator: ' ', omission: "... #{ link_to '(continue)', '#' }"), Sanitize::Config::BASIC).html_safe %>
Предоставляет выдержку с допустимым html.Я надеюсь, что это кому-нибудь поможет.
Теперь есть драгоценный камень под названием HTMLTruncator это позаботится об этом за вас.Я использовал его для отображения выдержек из постов и тому подобного, и он очень надежный.