ListingsToolkit refactoring (#16184)

This commit is contained in:
Michael Kohl 2022-01-21 09:27:10 +07:00 committed by GitHub
parent af2e1f0545
commit 6099d3640d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 70 additions and 26 deletions

View file

@ -16,10 +16,7 @@ module ListingsToolkit
# [@forem/oss] Not entirely sure what the intention behind the
# original code was, but at least this is more compact.
# [@forem/oss] Rails 6.1 adds `.compact` on ActionController::Parameters
# rubocop:disable Style/CollectionCompact
filtered_params = listing_params.reject { |_k, v| v.nil? }
# rubocop:enable Style/CollectionCompact
filtered_params = listing_params.compact
@listing.update(filtered_params)
end
@ -105,29 +102,9 @@ module ListingsToolkit
end
def create_listing(purchaser, cost)
successful_transaction = false
ActiveRecord::Base.transaction do
# subtract credits
Credits::Buyer.call(
purchaser: purchaser,
purchase: @listing,
cost: cost,
)
create_result = Listings::Create.call(@listing, purchaser: purchaser, cost: cost)
# save the listing
@listing.bumped_at = Time.current
@listing.published = true
@listing.originally_published_at = Time.current
# since we can't raise active record errors in this transaction
# due to the fact that we need to display them in the :new view,
# we manually rollback the transaction if there are validation errors
raise ActiveRecord::Rollback unless @listing.save
successful_transaction = true
end
if successful_transaction
if create_result.success?
rate_limiter.track_limit_by_action(:listing_creation)
clear_listings_cache
process_successful_creation

View file

@ -0,0 +1,50 @@
module Listings
# This service wraps listing purchses in a transaction which verifies that
# the purchaser has enough credits to complete this process.
class Create
# @param listing [Listing] an initialized but not yet persisted listing
# @param purchaser [User] the user attempting to purchase the listing
# @param cost [Integer] the number of credits the user has to spend
# @return [Listings::Create] the service itself, used for the success? check
def self.call(listing, purchaser:, cost:)
new(listing, purchaser, cost).call
end
def initialize(listing, purchaser, cost)
@listing = listing
@purchaser = purchaser
@cost = cost
@success = false
end
def call
ActiveRecord::Base.transaction do
# Subtract credits
enough_credits = Credits::Buyer.call(
purchaser: @purchaser,
purchase: @listing,
cost: @cost,
)
raise ActiveRecord::Rollback unless enough_credits
# Update the listing
@listing.bumped_at = Time.current
@listing.published = true
@listing.originally_published_at = Time.current
# Since we can't raise ActiveRecord errors in this transaction
# due to the fact that we need to display them in the :new view,
# we manually rollback the transaction if there are validation errors
raise ActiveRecord::Rollback unless @listing.save
@success = true
end
self
end
def success?
@success
end
end
end

View file

@ -0,0 +1,17 @@
require "rails_helper"
RSpec.describe Listings::Create, type: :service do
let(:user) { create(:user) }
let(:listing) { build(:listing, user: user) }
it "is successful when the purchaser has enough credits" do
create(:credit, user: user)
create_result = described_class.call(listing, purchaser: user, cost: 1)
expect(create_result.success?).to be true
end
it "fails if the purchaser doesn't have enough credits" do
create_result = described_class.call(listing, purchaser: user, cost: 1)
expect(create_result.success?).to be false
end
end