Module: ApplicationHelper
- Includes:
- IconHelper, Memery, UppyUploaderHelper, UrlsHelper, Www::ImagesHelper, Www::SeoHelper
- Included in:
- ApplicationController, SimpleController, VideoPlayerComponent, Www::AddToCartButtonComponent, Www::AssociationsSliderComponent, Www::BlogProductEmbedComponent, Www::CarouselSliderComponent, Www::CustomMatsPresenter, Www::HomepageProductsComponent, Www::ProductCardComponent, Www::ProductCatalogPresenter, Www::ProductLinePresenter, Www::TowelWarmersPresenter, Www::VideoCardComponent
- Defined in:
- app/helpers/application_helper.rb
Overview
View helper: application.
Constant Summary
Constants included from Www::SeoHelper
Www::SeoHelper::AWARDS, Www::SeoHelper::CA_ADDRESS, Www::SeoHelper::CA_BUSINESS_HOURS, Www::SeoHelper::CA_CONTACT_POINT, Www::SeoHelper::CA_CURRENCIES, Www::SeoHelper::CA_DESCRIPTION, Www::SeoHelper::CA_FOUNDING_DATE, Www::SeoHelper::CA_GLOBAL_LOCATION_NUMBER, Www::SeoHelper::CA_LEGAL_NAME, Www::SeoHelper::CA_LOCAL_BUSINESS, Www::SeoHelper::CA_ONLINE_STORE, Www::SeoHelper::CA_RETURN_POLICY, Www::SeoHelper::CA_SALES_DEPARTMENT, Www::SeoHelper::CA_SERVICE_AREA, Www::SeoHelper::CA_URL, Www::SeoHelper::CA_VAT_ID, Www::SeoHelper::CA_WAREHOUSE_DEPARTMENT, Www::SeoHelper::CA_WAREHOUSE_HOURS, Www::SeoHelper::COMPANY_EMAIL, Www::SeoHelper::COMPANY_LOGO, Www::SeoHelper::COMPANY_NAME, Www::SeoHelper::COMPANY_SLOGAN, Www::SeoHelper::EXPERTISE, Www::SeoHelper::FAX_NUMBER, Www::SeoHelper::GS1_COMPANY_PREFIX, Www::SeoHelper::ISO6523_CODE, Www::SeoHelper::PAYMENT_METHODS, Www::SeoHelper::PHONE_NUMBER, Www::SeoHelper::PRIMARY_NAICS, Www::SeoHelper::REFUND_TYPE, Www::SeoHelper::RETURN_FEES, Www::SeoHelper::RETURN_METHOD, Www::SeoHelper::RETURN_POLICY_CATEGORY, Www::SeoHelper::SECONDARY_NAICS, Www::SeoHelper::SOCIAL_PROFILES, Www::SeoHelper::US_ADDRESS, Www::SeoHelper::US_BUSINESS_HOURS, Www::SeoHelper::US_CONTACT_POINT, Www::SeoHelper::US_CURRENCIES, Www::SeoHelper::US_DESCRIPTION, Www::SeoHelper::US_FOUNDING_DATE, Www::SeoHelper::US_GLOBAL_LOCATION_NUMBER, Www::SeoHelper::US_IMAGE, Www::SeoHelper::US_LEGAL_NAME, Www::SeoHelper::US_LOCAL_BUSINESS, Www::SeoHelper::US_ONLINE_STORE, Www::SeoHelper::US_RETURN_POLICY, Www::SeoHelper::US_SALES_DEPARTMENT, Www::SeoHelper::US_SERVICE_AREA, Www::SeoHelper::US_TAX_ID, Www::SeoHelper::US_URL, Www::SeoHelper::US_WAREHOUSE_DEPARTMENT, Www::SeoHelper::US_WAREHOUSE_HOURS
Constants included from IconHelper
IconHelper::CUSTOM_ICON_MAP, IconHelper::CUSTOM_SVG_DIR, IconHelper::DEFAULT_FAMILY
Instance Method Summary collapse
- #better_number_to_currency(number, options = {}) ⇒ Object
- #check_force_logout ⇒ Object
-
#check_or_cross(value, options = {}) ⇒ Object
Truthy = green check mark other wise red stop.
- #check_or_times(value, _options = {}) ⇒ Object
-
#embedded_tab_frame_id ⇒ Object
Frame id for views that are embeddable inside ANY tab regardless of caller.
- #error_messages(object) ⇒ Object
- #general_disclaimer_on_product_installation_and_local_codes ⇒ Object
- #gridjs_from_html_table(table_id, **options) ⇒ Object
-
#gridjs_table(id, data: nil, columns: nil, **options) ⇒ Object
Grid.js helper methods for modern table functionality.
- #is_wy_ip ⇒ Object
- #line_break(string, compact = false) ⇒ Object
- #parent_layout(layout) ⇒ Object
- #pass_or_fail(result) ⇒ Object
- #render_error_messages_list(object) ⇒ Object
-
#render_video_card(video, layout: 'card', card_style: 'default', hide_title: false, hide_description: false, display_category_badge: false, display_duration: false, show_popup: true, show_direct_link: true, styles: '') ⇒ Object
Helper method to render video cards with consistent options.
- #resolved_auth_form_turbo_frame(turbo_frame: RESOLVED_AUTH_FRAME_UNSET) ⇒ Object
-
#return_path_or(default) ⇒ Object
Returns @return_path (set by Controllers::ReturnPathHandling) when present, otherwise falls back to the supplied default.
-
#safe_css_color(color) ⇒ Object
Validates a CSS color value against safe patterns (hex codes and named colors).
- #set_return_path_if_present(return_path: @return_path, return_title: nil) ⇒ Object
- #set_section_if_present ⇒ Object
-
#tab_frame_id ⇒ Object
Frame id for tab partial views.
- #to_underscore(term) ⇒ Object
- #track_page? ⇒ Boolean
-
#turbo_section_wrapper(id: nil, class_names: nil) ⇒ Object
Enable Turbo functionality for specific sections without affecting the entire page.
- #turbo_tabs_request? ⇒ Boolean
- #url_on_same_domain_as_request(path) ⇒ Object
-
#widget_index_daily_focus_index_path ⇒ Object
AppSignal #2131: legacy references used
widget_index_daily_focus_index_path; the route helper fromresources :daily_focuscollectionwidget_indexiswidget_index_daily_focus_path. - #working_hours? ⇒ Boolean
- #yes_or_no(value) ⇒ Object
- #yes_or_no_highlighted(b, reverse_check = false) ⇒ Object
- #yes_or_no_with_check_or_cross(b, reverse_check = false) ⇒ Object
- #youtube_video(url) ⇒ Object
Methods included from UppyUploaderHelper
#file_uploader, #image_uploader, #large_file_uploader_s3, #lead_sketch_uploader, #rma_image_uploader, #rma_image_uploader_s3, #uppy_uploader, #video_uploader
Methods included from Www::ImagesHelper
#image_asset_tag, #image_asset_url
Methods included from Www::SeoHelper
#add_page_schema, #add_webpage_schema, #canada?, #company_social_links, #ensure_context_json, #json_ld_script_tag, #local_business_schema, #online_store_id, #online_store_schema, #page_main_entity, #page_main_entity_json, #render_auto_collection_page_schema, #render_collection_page_schema, #render_local_business_schema, #render_online_store_schema, #render_page_schemas, #render_page_video_schemas, #render_webpage_schema, #render_webpage_schema_with_collections, #usa?
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?
Methods included from IconHelper
#account_nav_icon, #fa_icon, #star_rating_html
Instance Method Details
#better_number_to_currency(number, options = {}) ⇒ Object
96 97 98 99 100 101 |
# File 'app/helpers/application_helper.rb', line 96 def better_number_to_currency(number, = {}) return unless number strip_insignificant_zeros = ((number * 100) % 100).zero? # e.g 209.00 = 20900 % 100 = 0 therefore we can strip zero. but 209.20 we wouldn't want to render as 209.2 number_to_currency(number, .merge(strip_insignificant_zeros:, precision: 2)) end |
#check_force_logout ⇒ Object
245 246 247 248 249 250 251 |
# File 'app/helpers/application_helper.rb', line 245 def check_force_logout return unless current_user&.force_logout? current_user.update_column(:force_logout, false) sign_out(current_user.account) redirect_to request.original_url and return true end |
#check_or_cross(value, options = {}) ⇒ Object
Truthy = green check mark other wise red stop
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'app/helpers/application_helper.rb', line 122 def check_or_cross(value, = {}) if value.to_b [:title] = 'Yes' [:class] ||= 'text-green' [:style] ||= 'color:green;font-size:1.2em' check_icon = .delete(:check_icon) || 'check-circle' fa_icon(check_icon, **) else [:title] = 'No' [:class] ||= 'text-red' [:style] ||= 'color:red;font-size:1.2em' cross_icon = .delete(:cross_icon) || 'ban' fa_icon(cross_icon, **) end end |
#check_or_times(value, _options = {}) ⇒ Object
138 139 140 |
# File 'app/helpers/application_helper.rb', line 138 def check_or_times(value, = {}) check_or_cross(value, cross_icon: 'times') end |
#embedded_tab_frame_id ⇒ Object
Frame id for views that are embeddable inside ANY tab regardless of caller.
Use for dual-purpose views (search_and_show, generic list pages) that render
full-screen when navigated directly but should slot into the calling tab when
fetched via Turbo-Frame: tab-content-*. Unlike tab_frame_id, this does
NOT gate on a parent_id route param — the embedded view doesn't know its
caller's resource.
Falls back to tab_frame_id (controller-derived default) when there's no
tab-content-* header, so direct navigation still works.
326 327 328 329 330 331 |
# File 'app/helpers/application_helper.rb', line 326 def header = request.headers['Turbo-Frame'] return header if header&.start_with?('tab-content-') tab_frame_id end |
#error_messages(object) ⇒ Object
187 188 189 190 191 192 193 194 |
# File 'app/helpers/application_helper.rb', line 187 def (object) return unless object.errors.any? content_tag :div, class: 'card bg-danger' do content_tag(:div, "#{pluralize(object.errors.count, 'error')} prohibited this record from being saved:", class: 'card-title') + (object) end end |
#general_disclaimer_on_product_installation_and_local_codes ⇒ Object
241 242 243 |
# File 'app/helpers/application_helper.rb', line 241 def general_disclaimer_on_product_installation_and_local_codes GENERAL_DISCLAIMER_ON_PRODUCT_INSTALLATION_AND_LOCAL_CODES end |
#gridjs_from_html_table(table_id, **options) ⇒ Object
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'app/helpers/application_helper.rb', line 77 def gridjs_from_html_table(table_id, **) config = { search: false, pagination: false, sort: true, from: "##{table_id}" }.merge() stimulus_data = { controller: 'gridjs', gridjs_autoload_value: true, gridjs_config_value: config.to_json } content_tag(:div, data: stimulus_data, class: 'gridjs-wrapper') do content_tag(:div, '', data: { gridjs_target: 'table' }) end end |
#gridjs_table(id, data: nil, columns: nil, **options) ⇒ Object
Grid.js helper methods for modern table functionality
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'app/helpers/application_helper.rb', line 55 def gridjs_table(id, data: nil, columns: nil, **) config = { search: false, pagination: false, sort: true, resizable: false }.merge() stimulus_data = { controller: 'gridjs', gridjs_autoload_value: true, gridjs_config_value: config.to_json } stimulus_data[:gridjs_data_value] = data.to_json if data stimulus_data[:gridjs_columns_value] = columns.to_json if columns content_tag(:div, data: stimulus_data, class: 'gridjs-wrapper') do content_tag(:div, '', data: { gridjs_target: 'table' }, id: id) end end |
#is_wy_ip ⇒ Object
111 112 113 |
# File 'app/helpers/application_helper.rb', line 111 def is_wy_ip warmlyyours_ip? end |
#line_break(string, compact = false) ⇒ Object
181 182 183 184 185 |
# File 'app/helpers/application_helper.rb', line 181 def line_break(string, compact = false) res = string.to_s.strip.split(/[\n\r]/) res = res.select { |res| res.to_s.strip.present? } if compact res.join('<br>').html_safe end |
#parent_layout(layout) ⇒ Object
234 235 236 237 238 239 |
# File 'app/helpers/application_helper.rb', line 234 def parent_layout(layout) @view_flow.set(:layout, output_buffer) # this allows us to deal with random binary or non UTF-8 encoded input from the wild wild web and prevent mixing encodings which ruby/rails errors out on output = render(template: "layouts/#{layout}").force_encoding('UTF-8') self.output_buffer = ActionView::OutputBuffer.new(output) end |
#pass_or_fail(result) ⇒ Object
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'app/helpers/application_helper.rb', line 164 def pass_or_fail(result) return nil if result.nil? case result when 'pass' color = 'green' icon = 'check-circle' when 'fail' color = 'red' icon = 'times-circle' when 'unavailable', 'unchecked' color = 'orange' icon = 'exclamation-circle' end "#{content_tag(:span, result.titleize)} #{fa_icon(icon, style: "color:#{color};font-size:1.2em")}" end |
#render_error_messages_list(object) ⇒ Object
196 197 198 199 200 |
# File 'app/helpers/application_helper.rb', line 196 def (object) content_tag(:ul, class: 'list-group') do object.errors..map { |msg| content_tag(:li, msg, class: 'list-group-item') }.join.html_safe end end |
#render_video_card(video, layout: 'card', card_style: 'default', hide_title: false, hide_description: false, display_category_badge: false, display_duration: false, show_popup: true, show_direct_link: true, styles: '') ⇒ Object
Helper method to render video cards with consistent options
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'app/helpers/application_helper.rb', line 33 def render_video_card(video, layout: 'card', card_style: 'default', hide_title: false, hide_description: false, display_category_badge: false, display_duration: false, show_popup: true, show_direct_link: true, styles: '') return unless video # If video is already a presenter (from video_by_slug), use it directly # Otherwise, present it with Www::VideoPresenter video_presenter = video.is_a?(Www::VideoPresenter) ? video : present(video, Www::VideoPresenter) render Www::VideoCardComponent.new( video: video_presenter, layout: layout, card_style: card_style, hide_title: hide_title, hide_description: hide_description, display_category_badge: display_category_badge, display_duration: display_duration, show_popup: show_popup, show_direct_link: show_direct_link, styles: styles ) end |
#resolved_auth_form_turbo_frame(turbo_frame: RESOLVED_AUTH_FRAME_UNSET) ⇒ Object
24 25 26 27 28 |
# File 'app/helpers/application_helper.rb', line 24 def resolved_auth_form_turbo_frame(turbo_frame: RESOLVED_AUTH_FRAME_UNSET) return turbo_frame unless turbo_frame.equal?(RESOLVED_AUTH_FRAME_UNSET) params[:turbo_target].to_s == 'navbar-account-frame' ? 'navbar-account-frame' : nil end |
#return_path_or(default) ⇒ Object
Returns @return_path (set by Controllers::ReturnPathHandling) when present,
otherwise falls back to the supplied default. Used in views for "Cancel"
links and similar nav-context links — does NOT perform a redirect.
205 206 207 |
# File 'app/helpers/application_helper.rb', line 205 def return_path_or(default) @return_path || default end |
#safe_css_color(color) ⇒ Object
Validates a CSS color value against safe patterns (hex codes and named colors).
Returns nil for anything that could contain injection payloads.
266 267 268 269 270 271 272 273 |
# File 'app/helpers/application_helper.rb', line 266 def safe_css_color(color) return nil if color.blank? stripped = color.strip return stripped if stripped.match?(/\A#[0-9a-fA-F]{3,8}\z/) || stripped.match?(/\A[a-zA-Z]{1,30}\z/) nil end |
#set_return_path_if_present(return_path: @return_path, return_title: nil) ⇒ Object
209 210 211 212 213 214 |
# File 'app/helpers/application_helper.rb', line 209 def set_return_path_if_present(return_path: @return_path, return_title: nil) capture do concat hidden_field_tag(:return_path, return_path) if return_path.present? && url_on_same_domain_as_request(return_path) concat hidden_field_tag(:return_title, return_title) if return_title.present? end end |
#set_section_if_present ⇒ Object
226 227 228 |
# File 'app/helpers/application_helper.rb', line 226 def set_section_if_present hidden_field_tag :section, params[:section] if params[:section].present? end |
#tab_frame_id ⇒ Object
Frame id for tab partial views.
Returns the controller-derived tab-content-<controller_name> by default.
Echoes the caller's Turbo-Frame: tab-content-<parent> header only when
the URL carries the parent's <resource>_id route param — i.e. the request
is genuinely scoped to that parent (e.g. /customers/:customer_id/activities).
Why the parent_id gate:
When a top-level resource (e.g. /orders/:id) is requested via a Turbo Frame
fetch from inside a parent's tab (Turbo-Frame: tab-content-warehouses), we
want the response to contain tab-content-orders (this controller's own
frame), NOT tab-content-warehouses. The frame mismatch fires
turbo:frame-missing, which the global handler in turbo_stream_actions.js
upgrades to a full Drive visit — the right UX for clicking "into" a different
resource.
Without the gate, the show page's outer tab_panel frame would be echoed to
match the caller, the response would slot into the parent's tab as an empty
lazy shell, and the empty-shell trap would Drive-visit the inner tab URL —
the user lands on /orders/:id/tab_line_items instead of /orders/:id.
Embed-anywhere views (search/list views meant to render under any tab) should
use embedded_tab_frame_id instead — that one always echoes.
303 304 305 306 307 308 309 310 311 312 313 314 |
# File 'app/helpers/application_helper.rb', line 303 def tab_frame_id default = "tab-content-#{controller_name}" header = request.headers['Turbo-Frame'] return default unless header&.start_with?('tab-content-') return header if header == default parent_resource = header.delete_prefix('tab-content-') parent_id_param = "#{parent_resource.singularize}_id" return header if params[parent_id_param].present? default end |
#to_underscore(term) ⇒ Object
230 231 232 |
# File 'app/helpers/application_helper.rb', line 230 def to_underscore(term) term.tableize.singularize.tr(' ', '_') end |
#track_page? ⇒ Boolean
115 116 117 118 119 |
# File 'app/helpers/application_helper.rb', line 115 def track_page? (Rails.env.production? || Rails.env.staging?) && (@skip_analytics.nil? or @skip_analytics == false) && !warmlyyours_ip? end |
#turbo_section_wrapper(id: nil, class_names: nil) ⇒ Object
Enable Turbo functionality for specific sections without affecting the entire page
254 255 256 257 258 259 260 261 262 |
# File 'app/helpers/application_helper.rb', line 254 def turbo_section_wrapper(id: nil, class_names: nil, &) turbo_attrs = {} turbo_attrs[:id] = id if id turbo_attrs[:class] = class_names if class_names turbo_attrs[:'data-turbo'] = 'true' if @turbo_frames_enabled content_tag(:div, turbo_attrs, &) end |
#turbo_tabs_request? ⇒ Boolean
275 276 277 |
# File 'app/helpers/application_helper.rb', line 275 def turbo_tabs_request? request.headers['Turbo-Frame']&.start_with?('tab-content') end |
#url_on_same_domain_as_request(path) ⇒ Object
216 217 218 219 220 221 222 223 224 |
# File 'app/helpers/application_helper.rb', line 216 def url_on_same_domain_as_request(path) if path.present? && (uri = begin URI(path) rescue StandardError nil end) (uri.host.nil? or uri.host.index(request.host).present?) end end |
#widget_index_daily_focus_index_path ⇒ Object
AppSignal #2131: legacy references used widget_index_daily_focus_index_path; the route helper
from resources :daily_focus collection widget_index is widget_index_daily_focus_path.
335 336 337 |
# File 'app/helpers/application_helper.rb', line 335 def (...) (...) end |
#working_hours? ⇒ Boolean
107 108 109 |
# File 'app/helpers/application_helper.rb', line 107 def working_hours? Time.current.in_working_hours? end |
#yes_or_no(value) ⇒ Object
142 143 144 |
# File 'app/helpers/application_helper.rb', line 142 def yes_or_no(value) value.to_b ? 'Yes' : 'No' end |
#yes_or_no_highlighted(b, reverse_check = false) ⇒ Object
152 153 154 155 156 157 158 159 160 161 162 |
# File 'app/helpers/application_helper.rb', line 152 def yes_or_no_highlighted(b, reverse_check = false) return nil if b.nil? res = yes_or_no(b) color = if reverse_check res == 'Yes' ? 'red' : 'green' else res == 'Yes' ? 'green' : 'red' end content_tag(:span, res, style: "color:#{color}") end |
#yes_or_no_with_check_or_cross(b, reverse_check = false) ⇒ Object
146 147 148 149 150 |
# File 'app/helpers/application_helper.rb', line 146 def yes_or_no_with_check_or_cross(b, reverse_check = false) return nil if b.nil? "#{yes_or_no(b)} #{check_or_cross(reverse_check ? !b : b)}" end |
#youtube_video(url) ⇒ Object
103 104 105 |
# File 'app/helpers/application_helper.rb', line 103 def youtube_video(url) render partial: 'shared/video', locals: { url: } end |