Class: PostsController
- Inherits:
-
ApplicationController
- Object
- ActionController::Base
- ApplicationController
- PostsController
- Includes:
- ActionView::Helpers::TextHelper
- Defined in:
- app/controllers/posts_controller.rb
Overview
Public blog controller: post index, tag pages, individual posts, and
authenticated previews of unpublished posts and revisions.
Constant Summary
Constants included from Controllers::AnalyticsEvents
Controllers::AnalyticsEvents::MAX_QUEUED_EVENTS, Controllers::AnalyticsEvents::SESSION_KEY
Constants included from Controllers::ErrorRendering
Controllers::ErrorRendering::NON_CONTENT_PATH_PREFIXES
Instance Method Summary collapse
-
#index ⇒ void
Blog index: paginated published posts (excluding press releases/newsletters) with HTML, Turbo Stream (infinite scroll), and Atom formats plus edge caching.
-
#lookup ⇒ Object
GET /posts/lookup.
-
#preview ⇒ void
Renders a chrome-free preview of a post (optionally a specific revision) for the CRM iframe.
-
#show ⇒ void
Renders a published post with its paginated comments; supports a preview query flag.
-
#tag ⇒ void
Blog posts for one tag (
params[:id]), redirecting remapped tags to their canonical page; same formats and caching as the index.
Methods inherited from ApplicationController
#account_impersonated?, #add_to_flash, #after_sign_in_path_for, #bypass_forgery_protection?, #chat_enabled?, #cloudflare_cleared?, #default_catalog, #default_url_options, #enable_turbo_frames, #find_publication, #fix_invalid_accept_header, #init_js_utils, #is_globals_call?, #layout_by_resource, #locale_store, #redirect_to, #require_employee_for_crm, #set_base_host, #set_real_ip, #set_report_errors_for, #should_render_layout?, #skip_layout_for_turbo_frame?, #stamp_impersonation_context, #tab_frame_breakout_request?, #warmlyyours_canada_ip?, #warmlyyours_ip?, #y
Methods included from Controllers::ReturnPathHandling
#check_for_return_path, #redirect_to_return_path_or_default
Methods included from Controllers::AnalyticsEvents
#consume_queued_analytics_events, #registration_lead_type, #track_event
Methods included from Controllers::DeviceDetection
Methods included from Controllers::SubdomainDetection
#is_crm_request?, #is_www_request?, #json_request?
Methods included from Controllers::TurboSafeRedirect
Methods included from Controllers::TrackingDetection
#bot_request?, #gdpr_country?, #gdpr_country_data, #prevent_bots, #set_tracking_cookie, #track_visitor?
Methods included from Controllers::AcceleratedFileSending
#send_file_accelerated, #send_upload_accelerated
Methods included from Controllers::ErrorRendering
#excp_string, #mail_to_for_error_reporting, #render_400, #render_404, #render_406, #render_410, #render_500, #render_invalid_authenticity_token, #render_ip_spoof_error, #render_unpermitted_parameters, #safe_referer_or_fallback
Methods included from Controllers::TurnstileVerification
#load_turnstile_script_tag, #turnstile_lazy_widget, #turnstile_script_tag, #turnstile_widget, #validate_turnstile!
Methods included from Controllers::CloudflareCaching
edge_cached, #edge_cached_action?, #reset_cloudflare_cache, #set_cloudflare_cache, #skip_edge_cache!, #skip_session
Methods included from Controllers::Webpackable
#preload_webpack_fonts, #webpack_css_include, #webpack_css_url, #webpack_js_include, #wpd_is_running?
Methods included from Controllers::Localizable
#cloudflare_country_locale, #determine_request_locale, #geocoder_locale, #guest_user_locale_check, #locale_optional_www_auth_path?, #param_locale, #set_locale, #set_request_locale, #skip_localization?, #warmlyyours_ip_locale
Methods included from Controllers::Authenticable
#access_denied, #authenticate_account, #authenticate_account!, #authenticate_account_from_login_token!, #check_is_a_manager, #check_is_a_sales_manager, #check_is_an_admin, #check_is_an_employee, #check_party, #clear_mismatched_guest_user, #create_guest_user, #credentials?, #current_or_guest_user, #current_or_guest_user_id_read_only, #current_user, #devise_mapping, #fully_logged_in?, #generate_bot_id, #guest_user, #identifiable?, #init_current_user, #initialize_guest, #load_context_user, #logging_in, #resource, #resource_name, #restrict_access_for_non_employees, #scrubbed_request_path, #user_object, #warn_on_session_guest_id_leak
Methods included from UrlsHelper
#catalog_breadcrumb_links, #catalog_link, #catalog_link_for_product_line, #catalog_link_for_sku, #cms_link, #delocalized_path, #path_to_sales_product_sku, #path_to_sales_product_sku_for_product_line, #path_to_sales_product_sku_for_product_line_slug, #product_line_from_catalog_link, #protocol_neutral_url, #sanitize_external_url, #valid_external_url?
Instance Method Details
#index ⇒ void
This method returns an undefined value.
Blog index: paginated published posts (excluding press releases/newsletters) with
HTML, Turbo Stream (infinite scroll), and Atom formats plus edge caching.
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'app/controllers/posts_controller.rb', line 19 def index begin @pagy, @posts = pagy(Post.published.not_tagged_with('press-release', 'press-industry-report', 'newsletter').most_recent_first, limit: 8) rescue Pagy::OptionError # Invalid page parameter (e.g., page='), redirect to page 1 redirect_to(www_posts_path, status: :moved_permanently) && return end if @posts.empty? && @pagy.page > 1 # redirect to page 1 redirect_to(www_posts_path, status: :moved_permanently) && return end page_suffix = @pagy.page > 1 ? " | Page #{@pagy.page}" : '' @seo_title = "The Radiant Journal — Radiant Heating Blog#{page_suffix} | #{helpers.company_locale}" @seo_description = "Expert radiant heating blog — floor heating guides, installation tips, product comparisons, and design inspiration from the WarmlyYours team.#{page_suffix}" @seo_header = 'The Radiant Journal' return unless stale?(@posts, public: true) respond_to do |format| format.html do set_cloudflare_cache(time_in_secs: 4.hours.to_i, tags: %w[post]) fresh_when(etag: [@posts, I18n.locale, @pagy.page], last_modified: @posts.maximum(:updated_at), public: true) end format.turbo_stream do # Infinite scroll - allow browser caching but not edge caching # Use stale? pattern to avoid DoubleRenderError when fresh_when sends 304 return unless stale?(etag: [@posts, I18n.locale, @pagy.page], last_modified: @posts.maximum(:updated_at), public: false) render partial: '/posts/infinite_scroll' end format.atom do response.set_header('Access-Control-Allow-Origin', '*') response.set_header('Cache-Control', 'max-age=900') @posts = @posts.limit(100) end end end |
#lookup ⇒ Object
GET /posts/lookup
59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'app/controllers/posts_controller.rb', line 59 def lookup term = params[:q].to_s.strip scope = Post.published if term.present? ilike = "%#{ActiveRecord::Base.sanitize_sql_like(term)}%" scope = scope.where('LOWER(subject) LIKE LOWER(?) OR LOWER(slug) LIKE LOWER(?)', ilike, ilike) end results = scope.order(created_at: :desc).limit(10).pluck(:id, :subject, :slug) render json: { results: results.map { |id, subject, slug| { id: id, text: subject.presence || slug.presence || id.to_s } } } end |
#preview ⇒ void
This method returns an undefined value.
Renders a chrome-free preview of a post (optionally a specific revision) for the CRM iframe.
142 143 144 145 146 147 148 149 150 151 |
# File 'app/controllers/posts_controller.rb', line 142 def preview # Clean preview action without caching, navigation, or footer @post_comment = @post.post_comments.new @pagy_comments, @post_comments = pagy(@post.post_comments.published.only_parents.order(created_at: :desc), page: 1) respond_to do |format| format.html { render action: :show, layout: 'www/blog_preview' } format.any { redirect_to preview_post_path(@post, format: :html) } end end |
#show ⇒ void
This method returns an undefined value.
Renders a published post with its paginated comments; supports a preview query flag.
127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'app/controllers/posts_controller.rb', line 127 def show @preview_mode = params[:preview].to_b @post_comment = @post.post_comments.new @pagy_comments, @post_comments = pagy(@post.post_comments.published.only_parents.order(created_at: :desc)) return unless stale?(@post, public: true) && !params[:preview].to_b set_cloudflare_cache(tags: %w[post]) unless params[:preview].to_b respond_to do |format| format.html format.any { redirect_to post_path(@post, format: :html) } end end |
#tag ⇒ void
This method returns an undefined value.
Blog posts for one tag (params[:id]), redirecting remapped tags to their canonical
page; same formats and caching as the index.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'app/controllers/posts_controller.rb', line 75 def tag @tag = Addressable::URI.unescape(params[:id]).downcase remapped_tag = TAG_MAP[@tag].presence if remapped_tag # Is it a tag we have re-mapped? remapped_tag_id = Addressable::URI.escape(remapped_tag) redirect_to(tag_post_url(remapped_tag_id), page: params[:page], status: :moved_permanently) && return end begin @pagy, @posts = pagy(Post.published.most_recent_first.(@tag), limit: 8) rescue Pagy::OptionError # Invalid page parameter (e.g., page='), redirect to page 1 redirect_to(tag_post_path(@tag), status: :moved_permanently) && return end if @posts.empty? && @pagy.page > 1 # redirect to page 1 redirect_to(tag_post_path(@tag), status: :moved_permanently) && return end tag_name = @tag.humanize.titleize page_suffix = @pagy.page > 1 ? " | Page #{@pagy.page}" : '' @seo_title = "#{tag_name} — The Radiant Journal#{page_suffix} | #{view_context.company_locale}" @seo_description = "#{tag_name} articles from The Radiant Journal — expert radiant heating guides, tips, and inspiration from the WarmlyYours team.#{page_suffix}" @seo_header = tag_name # Use stale? to check freshness and return early if content hasn't changed # This prevents DoubleRenderError when fresh_when sends 304 Not Modified return unless stale?(etag: [@posts, I18n.locale, @pagy.page, @tag], last_modified: @posts.maximum(:updated_at), public: true) set_cloudflare_cache(time_in_secs: 4.hours.to_i, tags: %w[post]) respond_to do |format| format.html { render 'index', layout: should_render_layout? } format.turbo_stream do # Infinite scroll for tag pages - allow browser caching but not edge caching return unless stale?(etag: [@posts, I18n.locale, @pagy.page, @tag], last_modified: @posts.maximum(:updated_at), public: false) render partial: '/posts/infinite_scroll' end format.atom do response.set_header('Access-Control-Allow-Origin', '*') response.set_header('Cache-Control', 'max-age=900') @posts = @posts.limit(100) render 'index' end end end |