Module: ApplicationHelper
- Includes:
- IconHelper, Memery, UppyUploaderHelper, UrlsHelper, Www::ImagesHelper, Www::SeoHelper
- Included in:
- 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 collapse
- CF_WEB_ANALYTICS_SKIP_PATHS =
Paths kept OUT of Cloudflare Web Analytics: the account/cart/checkout funnel
(app telemetry, not the marketing site) and /support/request, which is
overwhelmingly email-security-scanner fetches of the link in support mail
rather than real visitors. Locale prefix optional. %r{\A/(?:[a-z]{2}-[A-Z]{2}/)?(?:my_account|my_cart|accounts|payments|support/request)(?:/|\z)}- MARKDOWN_ALLOWED_TAGS =
Rails' default safe list plus the table tags/attributes it omits — docling
spec tables are the whole reason for rendering Markdown, andcolspan/
rowspancarry their structure. Additive rather than hand-maintained so we
don't silently strip the 16 other tags Rails already considers safe
(abbr, cite, div, span, mark, small, …), several of which docling emits.img/srcare deliberately REMOVED: this content comes from third-party
PDFs, and a remotewould make a CRM viewer's browser fetch
an attacker-controlled URL, leaking their IP and the fact they opened the
page. Nothing is lost today — docling reduces images to<!-- image -->
placeholders (1,323 publications carry those; zero carry a remote image
URL). Rehost server-side first if inline images are ever wanted here. ( Rails::HTML5::SafeListSanitizer. - %w[img] + %w[table thead tbody tfoot tr th td] ).freeze
- MARKDOWN_ALLOWED_ATTRIBUTES =
Attribute counterpart to MARKDOWN_ALLOWED_TAGS: Rails' default safe list
pluscolspan/rowspan/alignfor docling's spec tables, minussrc
(see MARKDOWN_ALLOWED_TAGS for why remote images are stripped). ( Rails::HTML5::SafeListSanitizer.allowed_attributes - %w[src] + %w[colspan rowspan align] ).freeze
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 = {}) ⇒ String?
Like number_to_currency, but strips insignificant zeros from whole-dollar amounts.
-
#cf_web_analytics?(path = request.path) ⇒ Boolean
Whether to emit the Cloudflare Web Analytics beacon for this request.
-
#check_or_cross(value, options = {}) ⇒ String
Truthy = green check mark other wise red stop.
-
#check_or_times(value, _options = {}) ⇒ String
Like +check_or_cross+, but uses a "times" icon for falsy values.
-
#embedded_tab_frame_id ⇒ String
Frame id for views that are embeddable inside ANY tab regardless of caller.
-
#error_messages(object) ⇒ ActiveSupport::SafeBuffer?
Renders a danger card listing a record's validation errors.
-
#general_disclaimer_on_product_installation_and_local_codes ⇒ String
The general disclaimer shown for product installation and local codes.
-
#markdown_to_html(text, tags: MARKDOWN_ALLOWED_TAGS, attributes: MARKDOWN_ALLOWED_ATTRIBUTES) ⇒ ActiveSupport::SafeBuffer
Render Markdown as sanitized HTML for display in admin/CRM views.
-
#parent_layout(layout) ⇒ ActionView::OutputBuffer
Renders the current template output inside another layout.
-
#pass_or_fail(result) ⇒ String?
Colored label and icon for a pass/fail style result string.
-
#render_error_messages_list(object) ⇒ ActiveSupport::SafeBuffer
Renders a record's full error messages as a Bootstrap list group.
-
#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: '') ⇒ String?
Renders a video card with consistent options via Www::VideoCardComponent.
-
#resolved_auth_form_turbo_frame(turbo_frame: RESOLVED_AUTH_FRAME_UNSET) ⇒ String?
Resolves the Turbo Frame id wrapping the account login/register form.
-
#return_path_or(default) ⇒ String
Returns @return_path (set by Controllers::ReturnPathHandling) when present, otherwise falls back to the supplied default.
-
#safe_css_color(color) ⇒ String?
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) ⇒ ActiveSupport::SafeBuffer
Emits hidden +return_path+ / +return_title+ fields for form posts.
-
#set_section_if_present ⇒ ActiveSupport::SafeBuffer?
Emits a hidden +section+ field echoing +params[:section]+.
-
#tab_frame_id ⇒ String
Frame id for tab partial views.
-
#to_underscore(term) ⇒ String
Underscores a term for use as an identifier (tableized, singular).
-
#turbo_section_wrapper(id: nil, class_names: nil) ⇒ ActiveSupport::SafeBuffer
Enable Turbo functionality for specific sections without affecting the entire page.
-
#turbo_tabs_request? ⇒ Boolean
Whether the current request is a Turbo Frame fetch for a tab pane.
-
#url_on_same_domain_as_request(path) ⇒ Boolean?
Whether a URL/path belongs to the current request's host.
-
#working_hours? ⇒ Boolean
Whether the current time falls within business working hours.
-
#yes_or_no(value) ⇒ String
"Yes"/"No" label for a value coerced with +to_b+.
-
#yes_or_no_highlighted(b, reverse_check = false) ⇒ ActiveSupport::SafeBuffer?
"Yes"/"No" label in a green or red span.
-
#yes_or_no_with_check_or_cross(b, reverse_check = false) ⇒ String?
"Yes"/"No" label followed by a check or cross icon.
Methods included from UppyUploaderHelper
#file_uploader, #image_uploader, #large_file_uploader_s3, #lead_sketch_uploader, #public_warranty_card_uploader, #rma_image_uploader, #rma_image_uploader_s3, #uppy_uploader, #video_uploader, #warranty_card_uploader
Methods included from Www::ImagesHelper
#image_asset_tag, #image_asset_url, #picture_asset_tag
Methods included from Www::SeoHelper
#add_page_schema, #add_webpage_schema, #canada?, #collect_schema, #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 = {}) ⇒ String?
Like number_to_currency, but strips insignificant zeros from whole-dollar amounts
109 110 111 112 113 114 |
# File 'app/helpers/application_helper.rb', line 109 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 |
#cf_web_analytics?(path = request.path) ⇒ Boolean
Whether to emit the Cloudflare Web Analytics beacon for this request.
Production only — staging is its own Rails env, so it can't report into the
production RUM site. Path is the ONLY other dimension we gate on, and that is
deliberate: the beacon ships inside edge-cached HTML, and the path is part of
the cache key, so it varies safely per cached object. Visitor geo/consent
can NOT be decided server-side here — the same cached page is served to
everyone (see shared/_tracking_init, which is JS-driven for exactly this
reason).
35 36 37 |
# File 'app/helpers/application_helper.rb', line 35 def cf_web_analytics?(path = request.path) Rails.env.production? && !path.match?(CF_WEB_ANALYTICS_SKIP_PATHS) end |
#check_or_cross(value, options = {}) ⇒ String
Truthy = green check mark other wise red stop
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'app/helpers/application_helper.rb', line 132 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 = {}) ⇒ String
Like +check_or_cross+, but uses a "times" icon for falsy values.
154 155 156 |
# File 'app/helpers/application_helper.rb', line 154 def check_or_times(value, = {}) check_or_cross(value, cross_icon: 'times') end |
#embedded_tab_frame_id ⇒ String
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.
476 477 478 479 480 481 |
# File 'app/helpers/application_helper.rb', line 476 def header = request.headers['Turbo-Frame'] return header if header&.start_with?('tab-content-') tab_frame_id end |
#error_messages(object) ⇒ ActiveSupport::SafeBuffer?
Renders a danger card listing a record's validation errors.
221 222 223 224 225 226 227 228 |
# File 'app/helpers/application_helper.rb', line 221 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 ⇒ String
The general disclaimer shown for product installation and local codes.
317 318 319 |
# File 'app/helpers/application_helper.rb', line 317 def general_disclaimer_on_product_installation_and_local_codes GENERAL_DISCLAIMER_ON_PRODUCT_INSTALLATION_AND_LOCAL_CODES end |
#markdown_to_html(text, tags: MARKDOWN_ALLOWED_TAGS, attributes: MARKDOWN_ALLOWED_ATTRIBUTES) ⇒ ActiveSupport::SafeBuffer
Render Markdown as sanitized HTML for display in admin/CRM views.
Kramdown's GFM parser (already a dependency) handles the tables, headings and
lists that docling emits when it extracts a PDF. Output is always run through
Rails' sanitize — Kramdown passes raw HTML in the source straight through,
and the Markdown here comes from third-party documents, not from us.
For Sunny's chat responses use Assistant::ResponseFormatter instead: it adds
code-block extraction, copy/preview buttons and citation handling on top.
The allowlist is overridable because the default one is tuned for
third-party PDF text (see MARKDOWN_ALLOWED_TAGS on why it drops images).
Content we author ourselves — a showcase story, say — can afford a wider
list; it passes its own rather than getting a second Markdown pipeline.
506 507 508 509 |
# File 'app/helpers/application_helper.rb', line 506 def markdown_to_html(text, tags: MARKDOWN_ALLOWED_TAGS, attributes: MARKDOWN_ALLOWED_ATTRIBUTES) html = Kramdown::Document.new(text.to_s, input: 'GFM', auto_ids: false).to_html sanitize(html, tags: , attributes: attributes) end |
#parent_layout(layout) ⇒ ActionView::OutputBuffer
Renders the current template output inside another layout.
The layout output is forced to UTF-8 to tolerate random binary or
non-UTF-8 input from the wild wild web — mixing encodings errors out.
306 307 308 309 310 311 |
# File 'app/helpers/application_helper.rb', line 306 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) ⇒ String?
Colored label and icon for a pass/fail style result string.
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'app/helpers/application_helper.rb', line 199 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) ⇒ ActiveSupport::SafeBuffer
Renders a record's full error messages as a Bootstrap list group.
234 235 236 237 238 |
# File 'app/helpers/application_helper.rb', line 234 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: '') ⇒ String?
Renders a video card with consistent options via Www::VideoCardComponent.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'app/helpers/application_helper.rb', line 80 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) ⇒ String?
Resolves the Turbo Frame id wrapping the account login/register form.
55 56 57 58 59 |
# File 'app/helpers/application_helper.rb', line 55 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) ⇒ String
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.
246 247 248 |
# File 'app/helpers/application_helper.rb', line 246 def return_path_or(default) @return_path || default end |
#safe_css_color(color) ⇒ String?
Validates a CSS color value against safe patterns (hex codes and named colors).
Returns nil for anything that could contain injection payloads.
342 343 344 345 346 347 348 349 |
# File 'app/helpers/application_helper.rb', line 342 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) ⇒ ActiveSupport::SafeBuffer
Emits hidden +return_path+ / +return_title+ fields for form posts.
+return_path+ is only emitted when present and on the same domain as the
current request (see +url_on_same_domain_as_request+).
259 260 261 262 263 264 |
# File 'app/helpers/application_helper.rb', line 259 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 ⇒ ActiveSupport::SafeBuffer?
Emits a hidden +section+ field echoing +params[:section]+.
287 288 289 |
# File 'app/helpers/application_helper.rb', line 287 def set_section_if_present hidden_field_tag :section, params[:section] if params[:section].present? end |
#tab_frame_id ⇒ String
Frame id for tab partial views.
Returns the instance-scoped tab-content-<controller_name>-<id> by default
(tab-content-<controller_name> when the route has no :id, e.g.
dashboards). 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 :id suffix:
Without it, a record's show page and a sibling record's tab pane share
one frame id. Clicking an item link inside another item's kit-contents tab
(/items/4702 fetched with Turbo-Frame: tab-content-items) returned a
show page whose own tab_panel frame matched the caller, so Turbo slotted
an empty lazy shell into the pane and the empty-shell trap Drive-visited
the inner tab URL — a chrome-less fragment page. With instance scoping,
item 13140's pane is tab-content-items-13140 while item 4702's response
renders tab-content-items-4702: the mismatch fires turbo:frame-missing
and the global handler upgrades to a full Drive visit of the already-
fetched page — same-controller navigation now rides the same proven
breakout path as cross-controller navigation.
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-2), we
want the response to contain tab-content-orders-<id> (this controller's own
frame), NOT the parent's frame id. 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. Genuinely nested content (/customers/134/activities,
/quotes?customer_id=134) still echoes so it renders inside the parent pane.
The server-side partner is ApplicationController#tab_frame_breakout_request?,
which keeps the full layout on breakout responses so visit(response)
paints a complete page instead of a bare fragment.
Embed-anywhere views (search/list views meant to render under any tab) should
use embedded_tab_frame_id instead — that one always echoes.
400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 |
# File 'app/helpers/application_helper.rb', line 400 def tab_frame_id default = ['tab-content', controller_name, params[:id].presence].compact.join('-') header = request.headers['Turbo-Frame'] return default unless header&.start_with?('tab-content-') return header if header == default # Echo the parent pane's id only when this request is genuinely scoped to # that parent (`<resource>_id` param) AND the header's instance suffix — # when present — names that same record. Without the suffix check, a # request scoped to customer 134 issued from customer 999's pane would # echo the 999 pane and swap the wrong parent instance instead of # breaking out. Controller names never contain dashes, so the first # dash-segment is the resource and the rest is the instance id (which # itself may contain dashes, e.g. slugs); a suffix-less header comes from # legacy pages rendered before instance scoping and still echoes. resource, *instance = header.delete_prefix('tab-content-').split('-') suffix = instance.join('-') parent_id = params["#{resource.singularize}_id"].presence if parent_id return header if suffix.blank? || suffix == parent_id.to_s end # Same-record alias echo for member routes. FriendlyId (and any custom # to_param) gives one record several URL spellings: /product_lines/snow-melting # renders its pane with the slug suffix while the tab hrefs carry the # numeric id (or vice versa, or a historical slug). A fetch whose header # names THIS controller and whose suffix resolves to the SAME record the # controller loaded is an in-pane fetch, not a breakout to a sibling — # treating it as a breakout is what dumped bare tab fragments onto # /product_lines/:id/tab_items as a full-page visit. if resource == controller_name && suffix.present? record = controller.instance_variable_get(:"@#{controller_name.singularize}") return header if tab_frame_suffix_aliases_record?(record, suffix) end default end |
#to_underscore(term) ⇒ String
Underscores a term for use as an identifier (tableized, singular).
295 296 297 |
# File 'app/helpers/application_helper.rb', line 295 def to_underscore(term) term.tableize.singularize.tr(' ', '_') end |
#turbo_section_wrapper(id: nil, class_names: nil) ⇒ ActiveSupport::SafeBuffer
Enable Turbo functionality for specific sections without affecting the entire page
326 327 328 329 330 331 332 333 334 |
# File 'app/helpers/application_helper.rb', line 326 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
Whether the current request is a Turbo Frame fetch for a tab pane.
354 355 356 |
# File 'app/helpers/application_helper.rb', line 354 def turbo_tabs_request? request.headers['Turbo-Frame']&.start_with?('tab-content') end |
#url_on_same_domain_as_request(path) ⇒ Boolean?
Whether a URL/path belongs to the current request's host.
Relative paths (no host) count as same-domain; blank or unparseable input
returns nil.
273 274 275 276 277 278 279 280 281 |
# File 'app/helpers/application_helper.rb', line 273 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 |
#working_hours? ⇒ Boolean
Whether the current time falls within business working hours.
119 120 121 |
# File 'app/helpers/application_helper.rb', line 119 def working_hours? Time.current.in_working_hours? end |
#yes_or_no(value) ⇒ String
"Yes"/"No" label for a value coerced with +to_b+.
162 163 164 |
# File 'app/helpers/application_helper.rb', line 162 def yes_or_no(value) value.to_b ? 'Yes' : 'No' end |
#yes_or_no_highlighted(b, reverse_check = false) ⇒ ActiveSupport::SafeBuffer?
"Yes"/"No" label in a green or red span.
182 183 184 185 186 187 188 189 190 191 192 |
# File 'app/helpers/application_helper.rb', line 182 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) ⇒ String?
"Yes"/"No" label followed by a check or cross icon.
171 172 173 174 175 |
# File 'app/helpers/application_helper.rb', line 171 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 |