feat: add extra scopes support on rate class
parent
30b4ac9484
commit
96a5f67221
|
@ -19,8 +19,9 @@ module Rating
|
||||||
scope: %i[author_type resource_id resource_type scopeable_id scopeable_type]
|
scope: %i[author_type resource_id resource_type scopeable_id scopeable_type]
|
||||||
}
|
}
|
||||||
|
|
||||||
def self.create(author:, metadata:, resource:, scopeable: nil, value:)
|
def self.create(author:, extra_scopes:, metadata:, resource:, scopeable: nil, value:)
|
||||||
record = find_or_initialize_by(author: author, resource: resource, scopeable: scopeable)
|
attributes = { author: author, resource: resource, scopeable: scopeable }.merge(extra_scopes)
|
||||||
|
record = find_or_initialize_by(attributes)
|
||||||
|
|
||||||
return record if record.persisted? && value == record.value
|
return record if record.persisted? && value == record.value
|
||||||
|
|
||||||
|
@ -32,8 +33,10 @@ module Rating
|
||||||
record
|
record
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.rate_for(author:, resource:, scopeable: nil)
|
def self.rate_for(author:, extra_scopes: {}, resource:, scopeable: nil)
|
||||||
find_by author: author, resource: resource, scopeable: scopeable
|
attributes = { author: author, resource: resource, scopeable: scopeable }.merge(extra_scopes)
|
||||||
|
|
||||||
|
find_by attributes
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -6,8 +6,10 @@ RSpec.describe Rating::Rate, ':create' do
|
||||||
let!(:author) { create :author }
|
let!(:author) { create :author }
|
||||||
let!(:article) { create :article }
|
let!(:article) { create :article }
|
||||||
|
|
||||||
|
before(:all) { AddExtraScopesOnRatingRatesTable.new.change }
|
||||||
|
|
||||||
context 'with no scopeable' do
|
context 'with no scopeable' do
|
||||||
before { described_class.create author: author, metadata: {}, resource: article, value: 3 }
|
before { described_class.create author: author, extra_scopes: {}, metadata: {}, resource: article, value: 3 }
|
||||||
|
|
||||||
context 'when rate does not exist yet' do
|
context 'when rate does not exist yet' do
|
||||||
it 'creates a rate entry' do
|
it 'creates a rate entry' do
|
||||||
|
@ -32,7 +34,7 @@ RSpec.describe Rating::Rate, ':create' do
|
||||||
context 'when rate already exists' do
|
context 'when rate already exists' do
|
||||||
let!(:author_2) { create :author }
|
let!(:author_2) { create :author }
|
||||||
|
|
||||||
before { described_class.create author: author_2, metadata: {}, resource: article, value: 4 }
|
before { described_class.create author: author_2, extra_scopes: {}, metadata: {}, resource: article, value: 4 }
|
||||||
|
|
||||||
it 'creates one more rate entry' do
|
it 'creates one more rate entry' do
|
||||||
rates = described_class.where(author: [author, author_2]).order('created_at asc')
|
rates = described_class.where(author: [author, author_2]).order('created_at asc')
|
||||||
|
@ -67,7 +69,16 @@ RSpec.describe Rating::Rate, ':create' do
|
||||||
context 'with scopeable' do
|
context 'with scopeable' do
|
||||||
let!(:category) { create :category }
|
let!(:category) { create :category }
|
||||||
|
|
||||||
before { described_class.create author: author, metadata: {}, resource: article, scopeable: category, value: 3 }
|
before do
|
||||||
|
described_class.create(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: {},
|
||||||
|
metadata: {},
|
||||||
|
resource: article,
|
||||||
|
scopeable: category,
|
||||||
|
value: 3
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
context 'when rate does not exist yet' do
|
context 'when rate does not exist yet' do
|
||||||
it 'creates a rate entry' do
|
it 'creates a rate entry' do
|
||||||
|
@ -94,7 +105,16 @@ RSpec.describe Rating::Rate, ':create' do
|
||||||
context 'when rate already exists' do
|
context 'when rate already exists' do
|
||||||
let!(:author_2) { create :author }
|
let!(:author_2) { create :author }
|
||||||
|
|
||||||
before { described_class.create author: author_2, metadata: {}, resource: article, scopeable: category, value: 4 }
|
before do
|
||||||
|
described_class.create(
|
||||||
|
author: author_2,
|
||||||
|
extra_scopes: {},
|
||||||
|
metadata: {},
|
||||||
|
resource: article,
|
||||||
|
scopeable: category,
|
||||||
|
value: 4
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
it 'creates one more rate entry' do
|
it 'creates one more rate entry' do
|
||||||
rates = described_class.where(author: [author, author_2]).order('created_at asc')
|
rates = described_class.where(author: [author, author_2]).order('created_at asc')
|
||||||
|
@ -132,7 +152,7 @@ RSpec.describe Rating::Rate, ':create' do
|
||||||
context 'with metadata' do
|
context 'with metadata' do
|
||||||
context 'with nil value' do
|
context 'with nil value' do
|
||||||
it 'creates a rate entry ignoring metadata' do
|
it 'creates a rate entry ignoring metadata' do
|
||||||
described_class.create author: author, metadata: nil, resource: article, value: 3
|
described_class.create author: author, extra_scopes: {}, metadata: nil, resource: article, value: 3
|
||||||
|
|
||||||
rate = described_class.last
|
rate = described_class.last
|
||||||
|
|
||||||
|
@ -145,7 +165,7 @@ RSpec.describe Rating::Rate, ':create' do
|
||||||
|
|
||||||
context 'with empty value' do
|
context 'with empty value' do
|
||||||
it 'creates a rate entry ignoring metadata' do
|
it 'creates a rate entry ignoring metadata' do
|
||||||
described_class.create author: author, metadata: '', resource: article, value: 3
|
described_class.create author: author, extra_scopes: {}, metadata: '', resource: article, value: 3
|
||||||
|
|
||||||
rate = described_class.last
|
rate = described_class.last
|
||||||
|
|
||||||
|
@ -158,7 +178,13 @@ RSpec.describe Rating::Rate, ':create' do
|
||||||
|
|
||||||
context 'with hash value' do
|
context 'with hash value' do
|
||||||
it 'creates a rate entry with metadata included' do
|
it 'creates a rate entry with metadata included' do
|
||||||
described_class.create author: author, metadata: { comment: 'comment' }, resource: article, value: 3
|
described_class.create(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: {},
|
||||||
|
metadata: { comment: 'comment' },
|
||||||
|
resource: article,
|
||||||
|
value: 3
|
||||||
|
)
|
||||||
|
|
||||||
rate = described_class.last
|
rate = described_class.last
|
||||||
|
|
||||||
|
@ -169,4 +195,170 @@ RSpec.describe Rating::Rate, ':create' do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with extra scopes' do
|
||||||
|
let!(:category) { create :category }
|
||||||
|
|
||||||
|
it 'creates a rate entry' do
|
||||||
|
described_class.create(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: { scope_1: 'scope_1', scope_2: 'scope_2' },
|
||||||
|
metadata: {},
|
||||||
|
resource: article,
|
||||||
|
scopeable: category,
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
|
||||||
|
rate = described_class.last
|
||||||
|
|
||||||
|
expect(rate.author).to eq author
|
||||||
|
expect(rate.resource).to eq article
|
||||||
|
expect(rate.scope_1).to eq 'scope_1'
|
||||||
|
expect(rate.scope_2).to eq 'scope_2'
|
||||||
|
expect(rate.scopeable).to eq category
|
||||||
|
expect(rate.value).to eq 1
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates a rating entry' do
|
||||||
|
described_class.create(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: { scope_1: 'scope_1', scope_2: 'scope_2' },
|
||||||
|
metadata: {},
|
||||||
|
resource: article,
|
||||||
|
scopeable: category,
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
|
||||||
|
rating = Rating::Rating.last
|
||||||
|
|
||||||
|
expect(rating.average).to eq 1
|
||||||
|
expect(rating.estimate).to eq 1
|
||||||
|
expect(rating.resource).to eq article
|
||||||
|
expect(rating.scopeable).to eq category
|
||||||
|
expect(rating.sum).to eq 1
|
||||||
|
expect(rating.total).to eq 1
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when rate already exists' do
|
||||||
|
before do
|
||||||
|
described_class.create(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: { scope_1: 'scope_1', scope_2: 'scope_2' },
|
||||||
|
metadata: {},
|
||||||
|
resource: article,
|
||||||
|
scopeable: category,
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates the rate entry' do
|
||||||
|
described_class.create(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: { scope_1: 'scope_1', scope_2: 'scope_2' },
|
||||||
|
metadata: {},
|
||||||
|
resource: article,
|
||||||
|
scopeable: category,
|
||||||
|
value: 2
|
||||||
|
)
|
||||||
|
|
||||||
|
rates = described_class.all
|
||||||
|
|
||||||
|
expect(rates.size).to eq 1
|
||||||
|
|
||||||
|
rate = rates[0]
|
||||||
|
|
||||||
|
expect(rate.author).to eq author
|
||||||
|
expect(rate.resource).to eq article
|
||||||
|
expect(rate.scope_1).to eq 'scope_1'
|
||||||
|
expect(rate.scope_2).to eq 'scope_2'
|
||||||
|
expect(rate.scopeable).to eq category
|
||||||
|
expect(rate.value).to eq 2
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates the unique rating entry' do
|
||||||
|
described_class.create(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: { scope_1: 'scope_1', scope_2: 'scope_2' },
|
||||||
|
metadata: {},
|
||||||
|
resource: article,
|
||||||
|
scopeable: category,
|
||||||
|
value: 2
|
||||||
|
)
|
||||||
|
|
||||||
|
ratings = Rating::Rating.all
|
||||||
|
|
||||||
|
expect(ratings.size).to eq 1
|
||||||
|
|
||||||
|
rating = ratings[0]
|
||||||
|
|
||||||
|
expect(rating.average).to eq 2
|
||||||
|
expect(rating.estimate).to eq 2
|
||||||
|
expect(rating.resource).to eq article
|
||||||
|
expect(rating.scopeable).to eq category
|
||||||
|
expect(rating.sum).to eq 2
|
||||||
|
expect(rating.total).to eq 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when rate already exists but with at least one extra scope different' do
|
||||||
|
before do
|
||||||
|
described_class.create(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: { scope_1: 'scope_1', scope_2: 'scope_2' },
|
||||||
|
metadata: {},
|
||||||
|
resource: article,
|
||||||
|
scopeable: category,
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
|
||||||
|
described_class.create(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: { scope_1: 'scope_1', scope_2: 'scope_missing' },
|
||||||
|
metadata: {},
|
||||||
|
resource: article,
|
||||||
|
scopeable: category,
|
||||||
|
value: 2
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates a new rate entry' do
|
||||||
|
rates = described_class.all
|
||||||
|
|
||||||
|
expect(rates.size).to eq 2
|
||||||
|
|
||||||
|
rate = rates[0]
|
||||||
|
|
||||||
|
expect(rate.author).to eq author
|
||||||
|
expect(rate.resource).to eq article
|
||||||
|
expect(rate.scope_1).to eq 'scope_1'
|
||||||
|
expect(rate.scope_2).to eq 'scope_2'
|
||||||
|
expect(rate.scopeable).to eq category
|
||||||
|
expect(rate.value).to eq 1
|
||||||
|
|
||||||
|
rate = rates[1]
|
||||||
|
|
||||||
|
expect(rate.author).to eq author
|
||||||
|
expect(rate.resource).to eq article
|
||||||
|
expect(rate.scope_1).to eq 'scope_1'
|
||||||
|
expect(rate.scope_2).to eq 'scope_missing'
|
||||||
|
expect(rate.scopeable).to eq category
|
||||||
|
expect(rate.value).to eq 2
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates the unique rating entry' do
|
||||||
|
ratings = Rating::Rating.all
|
||||||
|
|
||||||
|
expect(ratings.size).to eq 1
|
||||||
|
|
||||||
|
rating = ratings[0]
|
||||||
|
|
||||||
|
expect(rating.average).to eq 1.5
|
||||||
|
expect(rating.estimate).to eq 1.5
|
||||||
|
expect(rating.resource).to eq article
|
||||||
|
expect(rating.scopeable).to eq category
|
||||||
|
expect(rating.sum).to eq 3
|
||||||
|
expect(rating.total).to eq 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,16 +6,20 @@ RSpec.describe Rating::Rate, ':rate_for' do
|
||||||
let!(:author) { create :author }
|
let!(:author) { create :author }
|
||||||
let!(:article) { create :article }
|
let!(:article) { create :article }
|
||||||
|
|
||||||
|
before(:all) { AddExtraScopesOnRatingRatesTable.new.change }
|
||||||
|
|
||||||
context 'with no scopeable' do
|
context 'with no scopeable' do
|
||||||
context 'when rate does not exist' do
|
context 'when rate does not exist' do
|
||||||
specify { expect(described_class.rate_for(author: author, resource: article)).to eq nil }
|
it { expect(described_class.rate_for(author: author, resource: article)).to eq nil }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when rate does not exist' do
|
context 'when rate exists' do
|
||||||
before { described_class.create author: author, metadata: {}, resource: article, value: 3 }
|
let!(:record) do
|
||||||
|
described_class.create author: author, extra_scopes: {}, metadata: {}, resource: article, value: 3
|
||||||
|
end
|
||||||
|
|
||||||
it 'returns the record' do
|
it 'returns the record' do
|
||||||
expect(described_class.rate_for(author: author, resource: article)).to eq described_class.last
|
expect(described_class.rate_for(author: author, resource: article)).to eq record
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -24,16 +28,79 @@ RSpec.describe Rating::Rate, ':rate_for' do
|
||||||
let!(:category) { create :category }
|
let!(:category) { create :category }
|
||||||
|
|
||||||
context 'when rate does not exist' do
|
context 'when rate does not exist' do
|
||||||
specify { expect(described_class.rate_for(author: author, resource: article, scopeable: category)).to eq nil }
|
it do
|
||||||
|
expect(described_class.rate_for(author: author, resource: article, scopeable: category)).to eq nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when rate does not exist' do
|
context 'when rate exists' do
|
||||||
before { described_class.create author: author, metadata: {}, resource: article, scopeable: category, value: 3 }
|
let!(:record) do
|
||||||
|
described_class.create(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: {},
|
||||||
|
metadata: {},
|
||||||
|
resource: article,
|
||||||
|
scopeable: category,
|
||||||
|
value: 3
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
it 'returns the record' do
|
it 'returns the record' do
|
||||||
query = described_class.rate_for(author: author, resource: article, scopeable: category)
|
query = described_class.rate_for(author: author, resource: article, scopeable: category)
|
||||||
|
|
||||||
expect(query).to eq described_class.last
|
expect(query).to eq record
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with extra scopes' do
|
||||||
|
let!(:category) { create :category }
|
||||||
|
|
||||||
|
context 'when matches all attributes including the extra scopes' do
|
||||||
|
let!(:record) do
|
||||||
|
described_class.create(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: { scope_1: 'scope_1', scope_2: 'scope_2' },
|
||||||
|
metadata: {},
|
||||||
|
resource: article,
|
||||||
|
scopeable: category,
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns the record' do
|
||||||
|
result = described_class.rate_for(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: { scope_1: 'scope_1', scope_2: 'scope_2' },
|
||||||
|
resource: article,
|
||||||
|
scopeable: category
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).to eq record
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when matches all attributes but at least one extra scopes' do
|
||||||
|
let!(:record) do
|
||||||
|
described_class.create(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: { scope_1: 'scope_1', scope_2: 'scope_2' },
|
||||||
|
metadata: {},
|
||||||
|
resource: article,
|
||||||
|
scopeable: category,
|
||||||
|
value: 1
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not return the record' do
|
||||||
|
result = described_class.rate_for(
|
||||||
|
author: author,
|
||||||
|
extra_scopes: { scope_1: 'scope_1', scope_2: 'scope_missing' },
|
||||||
|
resource: article,
|
||||||
|
scopeable: category
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(result).to eq nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddExtraScopesOnRatingRatesTable < ActiveRecord::Migration[5.0]
|
||||||
|
def change
|
||||||
|
add_column :rating_rates, :scope_1, :string
|
||||||
|
add_column :rating_rates, :scope_2, :string
|
||||||
|
|
||||||
|
remove_index :rating_rates, %i[author_id author_type resource_id resource_type scopeable_id scopeable_type]
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue