Class: AudienceMember
- Inherits:
-
ApplicationRecord
- Object
- ActiveRecord::Base
- ApplicationRecord
- AudienceMember
- Includes:
- Models::Auditable
- Defined in:
- app/models/audience_member.rb
Overview
== Schema Information
Table name: audience_members
Database name: primary
id :integer not null, primary key
active :boolean default(TRUE), not null
email_address :string
reconciled :boolean default(FALSE), not null
created_at :datetime not null
updated_at :datetime not null
creator_id :integer
customer_id :integer
audience_id :integer
updater_id :integer
Indexes
idx_audience_members_unique_customer (audience_id,customer_id) UNIQUE WHERE email_address IS NULL AND customer_id IS NOT NULL
idx_audience_members_unique_email (audience_id,email_address) UNIQUE WHERE email_address IS NOT NULL
index_audience_members_on_active (active)
index_audience_members_on_customer_id (customer_id)
index_audience_members_on_email_address (email_address)
Foreign Keys
fk_rails_... (customer_id => parties.id) ON DELETE => cascade
fk_rails_... (audience_id => audiences.id) ON DELETE => cascade
Constant Summary collapse
- ACTIVITY_DELIVERY_STATES =
campaign_delivery states that mean an email was actually transmitted or
attempted — the bar for "has seen activity" that forces archival over
deletion. pending/queued/suppressed/duplicate/exception sent nothing. %w[sent bounced].freeze
Constants included from Models::Auditable
Models::Auditable::ALWAYS_IGNORED
Constants included from Models::Schedulable
Models::Schedulable::SIMPLE_FORM_OPTIONS
Instance Attribute Summary collapse
-
#customer_id ⇒ Object
readonly
Validates customer id, audience id.
-
#email_address ⇒ Object
readonly
audience is optional (and nil once a audience_member is archived/detached), so guard the list-scoped validations with &.
-
#update_customer ⇒ Object
Returns the value of attribute update_customer.
Belongs to collapse
-
#audience ⇒ Audience?
The audience this record belongs to.
-
#customer ⇒ Customer?
The customer this record belongs to.
-
#email_preference ⇒ EmailPreference?
The email preference this record belongs to.
Methods included from Models::Auditable
Has many collapse
-
#campaign_deliveries ⇒ ActiveRecord::Relation<CampaignDelivery>
dependent: :destroy so a audience_member with NO delivery activity takes its (pending/suppressed/…) deliveries with it on hard-delete.
-
#campaigns ⇒ ActiveRecord::Relation<Campaign>
The associated campaigns.
-
#contact_points ⇒ ActiveRecord::Relation<ContactPoint>
The associated contact points.
Class Method Summary collapse
-
.active ⇒ ActiveRecord::Relation<AudienceMember>
A relation of AudienceMembers that are active.
-
.archived ⇒ ActiveRecord::Relation<AudienceMember>
A relation of AudienceMembers that are archived.
-
.inactive ⇒ ActiveRecord::Relation<AudienceMember>
A relation of AudienceMembers that are inactive.
-
.unarchived ⇒ ActiveRecord::Relation<AudienceMember>
A relation of AudienceMembers that are unarchived.
-
.with_campaign_activity ⇒ ActiveRecord::Relation<AudienceMember>
A relation of AudienceMembers that are with campaign activity.
-
.with_customer ⇒ ActiveRecord::Relation<AudienceMember>
A relation of AudienceMembers that are with customer.
Instance Method Summary collapse
-
#activate ⇒ Object
Activate.
-
#archive! ⇒ Boolean
Retain the audience_member for record-keeping: stamp archived_at and detach it from its list (the list is being removed; audience_id is nullable).
-
#archived? ⇒ Boolean
Whether this audience_member has been archived for record-keeping.
-
#deactivate ⇒ Object
Deactivate.
-
#determined_customer ⇒ Object
Determined customer.
-
#name ⇒ String
The name of the record.
-
#party ⇒ Object
Party.
-
#party_customer ⇒ Object
Party customer.
-
#populate_email_if_missing ⇒ Object
Populate email if missing.
-
#remove! ⇒ Boolean
The safe "remove a audience_member" entry point: archive it for record-keeping if it has delivery activity, otherwise hard-delete it (cascading its inert pending/suppressed deliveries).
-
#seen_campaign_activity? ⇒ Boolean
True once an email was actually transmitted to / attempted for this audience_member (a
sentorbounceddelivery exists). -
#update_linked_contact_points ⇒ Object
Update linked contact points.
Methods included from Models::Auditable
#all_skipped_columns, #audit_reference_data, #should_not_save_version, #stamp_record
Methods inherited from ApplicationRecord
ransackable_associations, ransackable_attributes, ransackable_scopes, ransortable_attributes, #to_relation
Methods included from Models::Schedulable
Methods included from Models::AfterCommittable
Methods included from Models::EventPublishable
Instance Attribute Details
#customer_id ⇒ Object (readonly)
Validates customer id, audience id.
Validations (if => proc { |s| s.audience&.customer? } ):
- Presence
- Uniqueness ({ scope: :audience_id, message: 'can only be present once on each audience' })
57 |
# File 'app/models/audience_member.rb', line 57 validates :customer_id, presence: true, uniqueness: { scope: :audience_id, message: 'can only be present once on each audience' }, if: proc { |s| s.audience&.customer? } |
#email_address ⇒ Object (readonly)
audience is optional (and nil once a audience_member is archived/detached),
so guard the list-scoped validations with &. — a nil list has no scope to
enforce uniqueness against.
Validations (if => proc { |s| s.audience&.email? } ):
- Email_format
- Presence
- Uniqueness ({ scope: :audience_id, message: 'can only be present once on each audience' })
55 |
# File 'app/models/audience_member.rb', line 55 validates :email_address, email_format: true, presence: true, uniqueness: { scope: :audience_id, message: 'can only be present once on each audience' }, if: proc { |s| s.audience&.email? } |
#update_customer ⇒ Object
Returns the value of attribute update_customer.
77 78 79 |
# File 'app/models/audience_member.rb', line 77 def update_customer @update_customer end |
Class Method Details
.active ⇒ ActiveRecord::Relation<AudienceMember>
A relation of AudienceMembers that are active. Active Record Scope
64 |
# File 'app/models/audience_member.rb', line 64 scope :active, -> { where(active: true) } |
.archived ⇒ ActiveRecord::Relation<AudienceMember>
A relation of AudienceMembers that are archived. Active Record Scope
66 |
# File 'app/models/audience_member.rb', line 66 scope :archived, -> { where.not(archived_at: nil) } |
.inactive ⇒ ActiveRecord::Relation<AudienceMember>
A relation of AudienceMembers that are inactive. Active Record Scope
65 |
# File 'app/models/audience_member.rb', line 65 scope :inactive, -> { where(active: false) } |
.unarchived ⇒ ActiveRecord::Relation<AudienceMember>
A relation of AudienceMembers that are unarchived. Active Record Scope
67 |
# File 'app/models/audience_member.rb', line 67 scope :unarchived, -> { where(archived_at: nil) } |
.with_campaign_activity ⇒ ActiveRecord::Relation<AudienceMember>
A relation of AudienceMembers that are with campaign activity. Active Record Scope
69 |
# File 'app/models/audience_member.rb', line 69 scope :with_campaign_activity, -> { where(id: CampaignDelivery.where(state: ACTIVITY_DELIVERY_STATES).select(:audience_member_id)) } |
.with_customer ⇒ ActiveRecord::Relation<AudienceMember>
A relation of AudienceMembers that are with customer. Active Record Scope
71 72 73 74 75 |
# File 'app/models/audience_member.rb', line 71 scope :with_customer, -> { joins("left outer JOIN contact_points on contact_points.id = (select max(id) from contact_points where contact_points.detail = audience_members.email_address) left outer JOIN parties contacts on contacts.id = contact_points.party_id and contacts.type = 'Contact' left outer JOIN parties customers on customers.id = coalesce(audience_members.customer_id, contacts.customer_id, contact_points.party_id)") } |
Instance Method Details
#activate ⇒ Object
Activate.
93 94 95 |
# File 'app/models/audience_member.rb', line 93 def activate update(active: true) end |
#archive! ⇒ Boolean
Retain the audience_member for record-keeping: stamp archived_at and detach it
from its list (the list is being removed; audience_id is nullable).
update_columns bypasses validations/callbacks — a detached audience_member has no
list to scope the email/customer uniqueness checks against.
121 122 123 |
# File 'app/models/audience_member.rb', line 121 def archive! update_columns(archived_at: Time.current, audience_id: nil) end |
#archived? ⇒ Boolean
Returns whether this audience_member has been archived for record-keeping.
111 112 113 |
# File 'app/models/audience_member.rb', line 111 def archived? archived_at.present? end |
#audience ⇒ Audience?
Returns the audience this record belongs to.
36 |
# File 'app/models/audience_member.rb', line 36 belongs_to :audience, inverse_of: :audience_members, optional: true |
#campaign_deliveries ⇒ ActiveRecord::Relation<CampaignDelivery>
dependent: :destroy so a audience_member with NO delivery activity takes its
(pending/suppressed/…) deliveries with it on hard-delete. AudienceMembers WITH
activity are archived instead (archive_instead_of_destroy_if_activity, which
aborts the destroy before this cascade runs), so their deliveries are kept.
46 |
# File 'app/models/audience_member.rb', line 46 has_many :campaign_deliveries, dependent: :destroy |
#campaigns ⇒ ActiveRecord::Relation<Campaign>
Returns the associated campaigns.
50 |
# File 'app/models/audience_member.rb', line 50 has_many :campaigns, through: :audience |
#contact_points ⇒ ActiveRecord::Relation<ContactPoint>
Returns the associated contact points.
48 |
# File 'app/models/audience_member.rb', line 48 has_many :contact_points, foreign_key: :detail, primary_key: :email_address |
#customer ⇒ Customer?
Returns the customer this record belongs to.
38 |
# File 'app/models/audience_member.rb', line 38 belongs_to :customer, optional: true |
#deactivate ⇒ Object
Deactivate.
98 99 100 |
# File 'app/models/audience_member.rb', line 98 def deactivate update(active: false) end |
#determined_customer ⇒ Object
Determined customer.
156 157 158 |
# File 'app/models/audience_member.rb', line 156 def determined_customer customer || party_customer end |
#email_preference ⇒ EmailPreference?
Returns the email preference this record belongs to.
40 |
# File 'app/models/audience_member.rb', line 40 belongs_to :email_preference, optional: true, primary_key: :email, foreign_key: :email_address |
#name ⇒ String
Returns the name of the record.
137 138 139 |
# File 'app/models/audience_member.rb', line 137 def name party&.full_name end |
#party ⇒ Object
Party.
142 143 144 |
# File 'app/models/audience_member.rb', line 142 def party contact_points.where.not(party_id: nil).first&.party end |
#party_customer ⇒ Object
Party customer.
147 148 149 150 151 152 153 |
# File 'app/models/audience_member.rb', line 147 def party_customer if party.respond_to?(:customer) party.customer else party end end |
#populate_email_if_missing ⇒ Object
Populate email if missing.
166 167 168 169 170 171 172 |
# File 'app/models/audience_member.rb', line 166 def populate_email_if_missing return if email_address.present? return unless audience&.email? return unless customer self.email_address = customer.email end |
#remove! ⇒ Boolean
The safe "remove a audience_member" entry point: archive it for record-keeping if
it has delivery activity, otherwise hard-delete it (cascading its inert
pending/suppressed deliveries). A bare #destroy is blocked for audience_members
with activity (see prevent_hard_delete_with_activity), so callers that mean
"remove from the list" should use this.
132 133 134 |
# File 'app/models/audience_member.rb', line 132 def remove! seen_campaign_activity? ? archive! : destroy! end |
#seen_campaign_activity? ⇒ Boolean
True once an email was actually transmitted to / attempted for this
audience_member (a sent or bounced delivery exists).
106 107 108 |
# File 'app/models/audience_member.rb', line 106 def seen_campaign_activity? campaign_deliveries.where(state: ACTIVITY_DELIVERY_STATES).exists? end |
#update_linked_contact_points ⇒ Object
Update linked contact points.
161 162 163 |
# File 'app/models/audience_member.rb', line 161 def update_linked_contact_points ContactPoint.where(detail: email_address_was).update_all(detail: email_address) end |