Class: Testimonials::PromptEvent
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- Testimonials::PromptEvent
- Defined in:
- app/models/testimonials/prompt_event.rb
Overview
The throttling ledger. Every auto-open is a "shown", every close without submitting is a "dismissed", every saved submission is a "submitted" — keyed by author_id for signed-in users, by a visitor cookie otherwise. eligible? reads this history so the widget never nags:
* submitted a testimonial -> never auto-prompted for one again
* submitted NPS -> not again within nps_reprompt_after
* shown or dismissed recently -> not again within reprompt_after
* shown max_prompts times -> never auto-prompted for that kind again
Explicit opens (the user clicked something) bypass all of this.
The ledger is optional: an install run with --skip-prompt-events has no table behind this class and config.prompt_events is false, so record! is a no-op and eligible? answers without a query. Every write and every read goes through the two methods below, so that flag is the only guard needed — nothing here asks the schema at runtime.
Constant Summary collapse
- KINDS =
%w[testimonial nps].freeze
- ACTIONS =
%w[shown dismissed submitted].freeze
Class Method Summary collapse
-
.eligible?(kind:, author_id: nil, visitor_token: nil, tenant: nil) ⇒ Boolean
Throttling is per-tenant: a user prompted in one tenant is still eligible in another, so each collection can ask independently.
- .record!(kind:, action:, author_id: nil, visitor_token: nil, tenant: nil) ⇒ Object
Class Method Details
.eligible?(kind:, author_id: nil, visitor_token: nil, tenant: nil) ⇒ Boolean
Throttling is per-tenant: a user prompted in one tenant is still eligible in another, so each collection can ask independently.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'app/models/testimonials/prompt_event.rb', line 39 def eligible?(kind:, author_id: nil, visitor_token: nil, tenant: nil) kind = kind.to_s return false unless KINDS.include?(kind) # No identity, no history: a brand-new visitor is always eligible. return true if .blank? && visitor_token.blank? # No ledger, no history either — the same answer, one flag earlier. # This is not a licence to nag: with the ledger off nothing auto-opens # (see WidgetHelper#testimonials_auto_open), and the one caller left is # the promoter offered the form inside a flow they opened themselves. return true unless Testimonials.config.prompt_events history = subject(, visitor_token, tenant).where(kind: kind) config = Testimonials.config return false if submitted_recently?(history, kind, config) return false if history.where(action: %w[shown dismissed]) .exists?(created_at: (Time.current - config.reprompt_after)..) history.where(action: 'shown').count < config.max_prompts end |
.record!(kind:, action:, author_id: nil, visitor_token: nil, tenant: nil) ⇒ Object
29 30 31 32 33 34 35 |
# File 'app/models/testimonials/prompt_event.rb', line 29 def record!(kind:, action:, author_id: nil, visitor_token: nil, tenant: nil) return unless Testimonials.config.prompt_events return if .blank? && visitor_token.blank? create!(kind: kind.to_s, action: action.to_s, tenant: tenant.presence, author_id: .presence, visitor_token: visitor_token.presence) end |