디제스트(Digest)에 몇 가지 내용을 추가하려고 합니다. 예전에는 템플릿을 오버라이드하는 방식으로 처리했는데, 지금은 이유를 알 수 없게 되어 그렇게 할 수 없습니다.
템플릿 오버라이드는 나쁜 관행이기 때문에, 디제스트 내의 일부 위치는 digest_custom_html로 대체됩니다. 하지만 이 메서드는 텍스트를 삽입하므로, 해당 부분에 .html_safe를 추가해야 합니다. 적어도 하나는 잘못된 위치에 있습니다(이름에는 "above"가 들어 있지만, 실제로는 아래에 위치해 있습니다).
이 문제는 제가 PR을 작성할 수 있는 수준의 기술력이 있다고 생각하지만, 너무 간단해서 다른 사람이 처리하는 것이 더 쉬울 수도 있습니다.
코어 변경 없이 제가 하고 싶은 것은 digest.html.erb 템플릿을 오버라이드하는 것입니다. 예전에는 app/views/user_notifications/digest.html.erb에 파일을 두면 코어에 있는 파일 대신 해당 파일이 처리되도록 할 수 있었습니다. 하지만 더 이상 그렇게 작동하지 않습니다.
이제 다음과 같은 멋진 digest_custom_html 기능이 있습니다:
민첩한 독자는 인기 있는 주제(Popular topics) 섹션이 277번째 줄보다 훨씬 앞선 78번째 줄 근처에서 시작한다는 것을 알아차릴 것입니다. 제가 잘못된 곳을 보고 있어서 아무것도 일어나지 않는다고 생각했던 데 얼마나 많은 시간을 보냈는지 정확히 알 수 없습니다. 하지만 본론에서 벗어났네요.
plugin.rb의 after_initialize에서 다음과 같이 구현하는 데 성공했습니다.
require_dependency "user_notifications"
module ::UserNotificationsHelperOverride
def digest_custom_html(position_key)
puts "doing improved the digest: #{position_key}"
if position_key == "below_popular_topics"
puts "doing the custom html for above_popular_topics"
# Custom HTML for the popular topics position
"<div class='custom-popular-topics'>MY COOOOOOOL TEXT</div>"
else
puts "doing the super for #{position_key}"
super
end
end
end
이 플러그인은 배포되었고, 곧 잊게 될 가능성이 높습니다. 따라서 digest_custom_html 필드를 의도된 대로 사용하려는 분이 계시다면, app.yml에 다음과 같은 코드를 추가하여 소스를 패치할 수 있습니다. 모든 것을 대체하는 정규식을 만드는 것은 귀찮아서, 제가 사용하던 것 하나만 처리했습니다. 필요에 맞게 수정해 주세요.
플러그인 내에서 템플릿을 만들어 app.yml에 포함할 수 있도록 했습니다. 이렇게 하면 YAML 블록 전체를 다루는 것보다 훨씬 간단합니다.
Hey @david. 이 PR에 관심이 있는 사람이 있는지 한 번 더 확인해 볼 생각입니다. 위에서 설명한 것처럼, 코드가 의도한 대로 작동하지 않는 것이 분명하지만, 아무도 신경 쓴 적이 없습니다. 배포 시 템플릿을 패치하는 방식으로 우회해 코드를 수정하여 배포했지만, 깔끔한 해결책은 아닙니다.
메서드 오버라이드의 결과에 .html_safe를 추가할 수 있을까요? erb 템플릿에 포함될 필요가 있다고 생각하지 않습니다.
Rails와 Ember 모두에서 일반적인 목표는 "이 문자열은 HTML 안전하다"는 표시를 작성/생성 지점에 최대한 가깝게 두는 것입니다. 이를 통해 개발자가 HTML이 실제로 안전한지(즉, 모든 사용자 입력이 이스케이프되었는지)를 확인해야 한다는 점이 매우 명확해집니다.
현재 하고 계신 방식은 (테스트가 되어 있다면) 괜찮지만, 이 메서드들의 “의도된” 사용법은 아닙니다. 의도된 플러그인 API였다면 다른 것들과 함께 plugin/instance.rb에 위치했을 것입니다.
이 메서드의 의도된 사용법은 마크다운을 일치하는 번역 키에 넣는 것입니다:
(거기에도 html_safe가 있다는 점에 유의하세요 - 모든 오버라이드에서 사용해야 하는 동일한 기법입니다)
오, 정말… 할 수 있다니!!! 템플릿의 위쪽(최소 내 머리속에서는) 렌더링되는 부분에 있는 것이 아니라, 바로 거기에 넣을 수 있다는 생각은 전혀 하지 못했거든요.
이제 digest_custom이 .html_safe를 호출한다는 것을 보고 이해하게 되었어요. 원하시는 대로, 제가 살펴보고 이해하려고 했던 코드에서요. 다만, 그 특이한 괄호 없는 문법을 사용한다는 점이 (제게는) 혼란스럽습니다. (아니면, 그냥 제가 그걸 발견하지 못했을 수도 있겠네요).
글쎄요, 로케일(로컬라이제이션)에서 값들은 볼 수 있지만, 전에 하던 것처럼 템플릿을 오버라이드하는 것과 비교하면, 이 방법은 훨씬 위험성이 적은 해결책입니다.
제 길을 제대로 안내해 주셔서 정말 감사합니다!
또 다른 한 가지, 제가 좀 어리석게 느끼는 일이 있습니다. 제 digest_custom_html은 렌더링되는 사용자를 필요로 하므로, digest를 오버라이드하여 @user를 설정하고 있습니다. 이렇게 하면 제 digets_custom_html이 다이제스트의 대상 사용자에게 접근할 수 있습니다. 이 과정을 피할 수 있는 아주 쉬운 방법이 있을까요?
after_initialize do
# Code which should run after Rails has finished booting
# require_relative "lib/discourse_add_jobs_to_digest/user_notifications_helper_override"
require_relative "lib/discourse_add_jobs_to_digest/engine"
require_relative "lib/discourse_add_jobs_to_digest/job_api"
require_dependency "user_notifications"
module ::UserNotificationsHelperOverride
def digest_custom_html(position_key)
if position_key == "above_footer"
DiscourseAddJobsToDigest::JobApi.get_jobs_html(@user).html_safe
else
super
end
end
end
UserNotificationsHelper.prepend(::UserNotificationsHelperOverride)
module ::UserNotificationsOverride
def digest(user, opts = {})
@user = user
super
end
end
UserNotifications.prepend(::UserNotificationsOverride)
end