From 10d1cdaf1ed050473115352271196f7f3277eaf8 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Fri, 4 Sep 2026 20:02:28 +0200 Subject: [PATCH] feat(posts): extend _comment and _post --- examples/blog/app/views/posts/_comment.erb | 28 +++++++++ examples/blog/app/views/posts/_post.erb | 23 ++++++- examples/blog/app/views/posts/edit.erb | 56 +++++++++++++++++ examples/blog/app/views/posts/index.erb | 70 +++++++++++++++++++--- 4 files changed, 168 insertions(+), 9 deletions(-) create mode 100644 examples/blog/app/views/posts/_comment.erb create mode 100644 examples/blog/app/views/posts/edit.erb diff --git a/examples/blog/app/views/posts/_comment.erb b/examples/blog/app/views/posts/_comment.erb new file mode 100644 index 0000000..ede337e --- /dev/null +++ b/examples/blog/app/views/posts/_comment.erb @@ -0,0 +1,28 @@ +
  • + <%= comment.author %> + <% unless comment.approved? %> + <%= t("comments.status_#{comment.status}") %> + <% end %> +

    <%= comment.body %>

    +

    + <%= t('likes.count', count: likes_count(comment)) %> + <% if user_signed_in? %> + <% own_like = current_user_like(comment) %> + <% if own_like %> + <%== button_to(t('likes.unlike'), "/likes/#{own_like.id}", method: :delete) %> + <% else %> + <%== button_to(t('likes.like'), "/likes?likeable_type=Comment&likeable_id=#{comment.id}") %> + <% end %> + <% end %> +

    + <% if current_user && current_user.id == comment.user_id %> + <%== link_to(t('comments.edit_link'), url_for(:edit_comment, post_id: post.to_param, id: comment.id)) %> + <%== button_to(t('comments.delete'), "/posts/#{post.to_param}/comments/#{comment.id}", method: :delete, data_confirm: t('comments.confirm_delete')) %> + <% end %> + <% if current_user && current_user.id == post.user_id && !comment.approved? %> + <%== button_to(t('comments.approve'), "/posts/#{post.to_param}/comments/#{comment.id}/approve", method: :patch) %> + <% end %> + <% if current_user && current_user.id == post.user_id && !comment.rejected? %> + <%== button_to(t('comments.reject'), "/posts/#{post.to_param}/comments/#{comment.id}/reject", method: :patch) %> + <% end %> +
  • diff --git a/examples/blog/app/views/posts/_post.erb b/examples/blog/app/views/posts/_post.erb index ca3f80c..3044d4e 100644 --- a/examples/blog/app/views/posts/_post.erb +++ b/examples/blog/app/views/posts/_post.erb @@ -1,4 +1,23 @@ -
  • -

    <%= post.title %>

    +
  • +

    <%== link_to(post.title, url_for(:post, slug: post.to_param)) %>

    + <% if post.featured %> + + <% end %> + <% if featured_only && post.featured && user_signed_in? && current_user.id == post.user_id %> + + <% end %> + <% if post.cover %> +

    <%= post.title %>

    + <% end %>

    <%= post.body %>

    +

    <%= t('posts.comments_count', count: post.comments_count) %>

    +

    <%= t('posts.last_activity', when: l(post.updated_at)) %>

    +

    <%== link_to(t('posts.read_more'), url_for(:post, slug: post.to_param)) %>

  • diff --git a/examples/blog/app/views/posts/edit.erb b/examples/blog/app/views/posts/edit.erb new file mode 100644 index 0000000..d2d9c46 --- /dev/null +++ b/examples/blog/app/views/posts/edit.erb @@ -0,0 +1,56 @@ +

    <%= t('posts.edit_heading') %>

    + +<% unless errors.empty? %> +

    <%= t('posts.errors_heading') %>

    + +<% end %> + +<% form_for(post, url: url_for(:post, slug: post.to_param)) do |f| %> + <%== f.hidden_field(:lock_version) %> +

    + <%== f.label(:title, t('posts.title_label')) %> + <%== f.text_field(:title) %> + <%== f.error_messages(:title) %> +

    +

    + <%== f.label(:body, t('posts.body_label')) %> + <%== f.text_area(:body) %> + <%== f.error_messages(:body) %> +

    +

    + <%== f.check_box(:featured) %> + <%== f.label(:featured, t('posts.featured_label')) %> +

    +

    + <%== f.label(:giveaway_slots, t('claims.giveaway_slots_label')) %> + <%== f.text_field(:giveaway_slots) %> + <%== f.error_messages(:giveaway_slots) %> +

    + <%== f.submit(t('posts.update_submit')) %> + <%== f.submit(t('posts.preview_submit'), formaction: url_for(:preview_post, slug: post.to_param)) %> + +

    <%= t('posts.moderate_comments_heading') %>

    + <% moderated_comments = post.comments.order(:created_at, :desc).to_a %> + <% if moderated_comments.empty? %> +

    <%= t('posts.moderate_comments_empty') %>

    + <% else %> + <% f.fields_for(:comments, moderated_comments) do |cf| %> +

    + <%== cf.hidden_field(:id) %> + <%== cf.label(:body, t('posts.moderate_comment_body_label')) %> + <%== cf.text_area(:body) %> + <%== cf.error_messages(:body) %> + +

    + <% end %> + <% end %> +<% end %> + +

    <%== link_to(t('posts.back_to_list'), url_for(:posts)) %>

    diff --git a/examples/blog/app/views/posts/index.erb b/examples/blog/app/views/posts/index.erb index abbf442..3f6d10a 100644 --- a/examples/blog/app/views/posts/index.erb +++ b/examples/blog/app/views/posts/index.erb @@ -1,21 +1,77 @@ -

    Blog

    +<% content_for(:sidebar) do %> + <%# Deliberately NOT keyed on current_user, unlike the fresh_when etag on this same action: the 5 most recent post titles/links are identical for every viewer, and the signed-in-as banner + new-post form that DO vary per viewer render outside this block, never inside the cached fragment. See prism-postep.md session 62/64. %> + <% cache(:recent_posts_sidebar, expires_in: 60) do %> +

    <%= t('posts.recent_heading') %>

    + + <% end %> +<% end %> + <% if notice %>

    <%= notice %>

    <% end %> <% unless errors.empty? %> +

    <%= t('posts.errors_heading') %>

    <% end %> -
    - - - -
    + +<% if user_signed_in? %> +

    <%= t('posts.new_post_heading') %>

    +<% form_for(new_post, url: url_for(:posts), html: { enctype: 'multipart/form-data' }) do |f| %> +

    + <%== f.label(:title, t('posts.title_label')) %> + <%== f.text_field(:title) %> + <%== f.error_messages(:title) %> +

    +

    + <%== f.label(:body, t('posts.body_label')) %> + <%== f.text_area(:body) %> + <%== f.error_messages(:body) %> +

    +

    + <%== f.label(:cover, t('posts.cover_label')) %> + <%== f.tag(:input, type: 'file', name: 'post[cover]', id: 'post_cover') %> +

    +

    + <%== f.check_box(:featured) %> + <%== f.label(:featured, t('posts.featured_label')) %> +

    +

    + <%== f.label(:giveaway_slots, t('claims.giveaway_slots_label')) %> + <%== f.text_field(:giveaway_slots) %> + <%== f.error_messages(:giveaway_slots) %> +

    + <%== f.submit(t('posts.submit')) %> +<% end %> + +

    <%= t('posts.import_heading') %>

    +<% form_for(Post.new, url: url_for(:import_posts), method: :post, html: { enctype: 'multipart/form-data' }) do |f| %> +

    + <%== f.label(:file, t('posts.import_label')) %> + <%== f.tag(:input, type: 'file', name: 'file', id: 'post_file', accept: '.csv,text/csv') %> +

    + <%== f.submit(t('posts.import_submit')) %> +<% end %> +<% end %> + +

    + <%== link_to(t('posts.filter_all'), url_for(:posts)) %> + | <%== link_to(t('posts.filter_recent', days: 7), "#{url_for(:posts)}?days=7") %> + | <%== link_to(t('posts.filter_recent', days: 30), "#{url_for(:posts)}?days=30") %> + | <%== link_to(t('posts.filter_featured'), "#{url_for(:posts)}?featured=1") %> +

    + + +<%== paginate(posts, path: ->(page) { "#{url_for(:posts)}?page=#{page}#{days.positive? ? "&days=#{days}" : ''}#{featured_only ? '&featured=1' : ''}" }) %>