[deploy] Email signups liquid tag backend (#8375)
* Backend MVP - Migration - Model - Associations * Add factory, spec, and validations - Add unqiue index for validations * Fix specs * Add author to email_subscriptions * Add user association to set_author_id * Add clarifying comment to set_author_id * Writing is hard sometimes * Rename email_subscriptions to subscription_sources * UserSubscription and user_subscription_sourceable * subscribers --> sourced_subscribers * Add comment to explain UserSubscription model
This commit is contained in:
parent
80d2b731b1
commit
6af063eebf
7 changed files with 75 additions and 1 deletions
|
|
@ -28,6 +28,8 @@ class Article < ApplicationRecord
|
|||
counter_culture :organization
|
||||
|
||||
has_many :comments, as: :commentable, inverse_of: :commentable
|
||||
has_many :user_subscriptions, as: :user_subscription_sourceable
|
||||
has_many :sourced_subscribers, class_name: "User", through: :user_subscriptions, source: :subscriber, foreign_key: :user_id
|
||||
has_many :top_comments,
|
||||
-> { where("comments.score > ? AND ancestry IS NULL and hidden_by_commentable_user is FALSE and deleted is FALSE", 10).order("comments.score DESC") },
|
||||
as: :commentable,
|
||||
|
|
|
|||
|
|
@ -67,6 +67,8 @@ class User < ApplicationRecord
|
|||
has_many :display_ad_events, dependent: :destroy
|
||||
has_many :email_authorizations, dependent: :delete_all
|
||||
has_many :email_messages, class_name: "Ahoy::Message", dependent: :destroy
|
||||
has_many :user_subscriptions, foreign_key: :author_id, inverse_of: :author, dependent: :destroy
|
||||
has_many :subscribers, through: :user_subscriptions, dependent: :destroy
|
||||
has_many :field_test_memberships, class_name: "FieldTest::Membership", as: :participant, dependent: :destroy
|
||||
has_many :github_repos, dependent: :destroy
|
||||
has_many :html_variants, dependent: :destroy
|
||||
|
|
|
|||
15
app/models/user_subscription.rb
Normal file
15
app/models/user_subscription.rb
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# This model handles a user (subscriber) subscribing to another user (author).
|
||||
# We also record the source of the subscription (Article, Comment, etc.) via a
|
||||
# polymorphic association (user_subscription_source/able).
|
||||
class UserSubscription < ApplicationRecord
|
||||
ALLOWED_TYPES = %w[Article].freeze
|
||||
|
||||
belongs_to :author, class_name: "User", foreign_key: :author_id, inverse_of: :user_subscriptions
|
||||
belongs_to :subscriber, class_name: "User", foreign_key: :subscriber_id, inverse_of: :user_subscriptions
|
||||
belongs_to :user_subscription_sourceable, polymorphic: true
|
||||
|
||||
validates :author_id, presence: true
|
||||
validates :subscriber_id, presence: true, uniqueness: { scope: %i[user_subscription_sourceable_type user_subscription_sourceable_id] }
|
||||
validates :user_subscription_sourceable_id, presence: true
|
||||
validates :user_subscription_sourceable_type, presence: true, inclusion: { in: ALLOWED_TYPES }
|
||||
end
|
||||
18
db/migrate/20200609192545_create_user_subscriptions.rb
Normal file
18
db/migrate/20200609192545_create_user_subscriptions.rb
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
class CreateUserSubscriptions < ActiveRecord::Migration[6.0]
|
||||
def change
|
||||
create_table :user_subscriptions do |t|
|
||||
t.references :user_subscription_sourceable, polymorphic: true, null: false, index: { name: :index_on_user_subscription_sourcebable_type_and_id }
|
||||
t.references :subscriber, references: :users, foreign_key: { to_table: :users }, null: false
|
||||
t.references :author, references: :users, foreign_key: { to_table: :users }, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
add_index(
|
||||
:user_subscriptions,
|
||||
%i[subscriber_id user_subscription_sourceable_id user_subscription_sourceable_type],
|
||||
unique: true,
|
||||
name: :index_on_subscriber_id_user_subscription_sourceable_type_and_id
|
||||
)
|
||||
end
|
||||
end
|
||||
17
db/schema.rb
17
db/schema.rb
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2020_06_09_191943) do
|
||||
ActiveRecord::Schema.define(version: 2020_06_09_192545) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
|
@ -1140,6 +1140,19 @@ ActiveRecord::Schema.define(version: 2020_06_09_191943) do
|
|||
t.index ["user_id"], name: "index_user_optional_fields_on_user_id"
|
||||
end
|
||||
|
||||
create_table "user_subscriptions", force: :cascade do |t|
|
||||
t.bigint "author_id", null: false
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.bigint "subscriber_id", null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
t.bigint "user_subscription_sourceable_id", null: false
|
||||
t.string "user_subscription_sourceable_type", null: false
|
||||
t.index ["author_id"], name: "index_user_subscriptions_on_author_id"
|
||||
t.index ["subscriber_id", "user_subscription_sourceable_id", "user_subscription_sourceable_type"], name: "index_on_subscriber_id_user_subscription_sourceable_type_and_id", unique: true
|
||||
t.index ["subscriber_id"], name: "index_user_subscriptions_on_subscriber_id"
|
||||
t.index ["user_subscription_sourceable_type", "user_subscription_sourceable_id"], name: "index_on_user_subscription_sourcebable_type_and_id"
|
||||
end
|
||||
|
||||
create_table "users", id: :serial, force: :cascade do |t|
|
||||
t.integer "articles_count", default: 0, null: false
|
||||
t.string "available_for"
|
||||
|
|
@ -1326,6 +1339,8 @@ ActiveRecord::Schema.define(version: 2020_06_09_191943) do
|
|||
add_foreign_key "user_blocks", "users", column: "blocker_id"
|
||||
add_foreign_key "user_counters", "users", on_delete: :cascade
|
||||
add_foreign_key "user_optional_fields", "users"
|
||||
add_foreign_key "user_subscriptions", "users", column: "author_id"
|
||||
add_foreign_key "user_subscriptions", "users", column: "subscriber_id"
|
||||
add_foreign_key "users_roles", "users", on_delete: :cascade
|
||||
add_foreign_key "webhook_endpoints", "oauth_applications"
|
||||
add_foreign_key "webhook_endpoints", "users"
|
||||
|
|
|
|||
8
spec/factories/user_subscription.rb
Normal file
8
spec/factories/user_subscription.rb
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
FactoryBot.define do
|
||||
factory :user_subscription do
|
||||
association :subscriber, factory: :user, strategy: :create
|
||||
association :user_subscription_sourceable, factory: :article
|
||||
|
||||
author { user_subscription_sourceable.user }
|
||||
end
|
||||
end
|
||||
14
spec/models/user_subscription_spec.rb
Normal file
14
spec/models/user_subscription_spec.rb
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe UserSubscription, type: :model do
|
||||
subject { build(:user_subscription) }
|
||||
|
||||
describe "validations" do
|
||||
it { is_expected.to validate_presence_of(:user_subscription_sourceable_id) }
|
||||
it { is_expected.to validate_presence_of(:user_subscription_sourceable_type) }
|
||||
it { is_expected.to validate_presence_of(:subscriber_id) }
|
||||
it { is_expected.to validate_presence_of(:author_id) }
|
||||
it { is_expected.to validate_inclusion_of(:user_subscription_sourceable_type).in_array(%w[Article]) }
|
||||
it { is_expected.to validate_uniqueness_of(:subscriber_id).scoped_to(:user_subscription_sourceable_type, :user_subscription_sourceable_id) }
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue