Skip to content

Commit

Permalink
Merge pull request #2 from wbotelhos/adding-table-config
Browse files Browse the repository at this point in the history
Adding table config
  • Loading branch information
wbotelhos authored Feb 14, 2018
2 parents 754aaca + 7247a25 commit 719a603
Show file tree
Hide file tree
Showing 26 changed files with 343 additions and 31 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.byebug_history
*.gem
/config
10 changes: 5 additions & 5 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ GEM
arel (8.0.0)
ast (2.4.0)
builder (3.2.3)
byebug (9.1.0)
byebug (10.0.0)
coderay (1.1.2)
concurrent-ruby (1.0.5)
crass (1.0.3)
Expand All @@ -46,9 +46,9 @@ GEM
factory_bot_rails (4.8.2)
factory_bot (~> 4.8.2)
railties (>= 3.0.0)
i18n (0.9.3)
i18n (0.9.5)
concurrent-ruby (~> 1.0)
loofah (2.1.1)
loofah (2.2.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
method_source (0.9.0)
Expand All @@ -64,8 +64,8 @@ GEM
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry-byebug (3.5.1)
byebug (~> 9.1)
pry-byebug (3.6.0)
byebug (~> 10.0)
pry (~> 0.10)
rack (2.0.4)
rack-test (0.8.2)
Expand Down
26 changes: 26 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,29 @@ require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new

task default: :spec

desc 'Runs tests with config enabled'
task :spec_config do
directory_config = File.expand_path('config')
unsafe_path = ['', '/', '.', './'].include?(directory_config)

`mkdir -p #{directory_config}`

File.open(File.expand_path('config/rating.yml'), 'w+') do |file|
file.write "rating:\n rate_table: 'reviews'\n rating_table: 'review_ratings'"
end

ENV['CONFIG_ENABLED'] = 'true'

Rake::Task['spec'].invoke

FileUtils.rm_rf(directory_config) unless unsafe_path
end

desc 'Runs tests with and without config enabled'
task :spec do
Rake::Task['spec'].invoke
Rake::Task['spec_config'].invoke

puts "Spec with and without config enabled executed."
end
2 changes: 1 addition & 1 deletion lib/generators/rating/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Rating
class InstallGenerator < Rails::Generators::Base
source_root File.expand_path('../templates', __FILE__)

desc 'creates Rating migration'
desc 'Creates Rating migration'

def create_migration
template 'db/migrate/create_rating_table.rb', "db/migrate/#{timestamp(0)}_create_rating_table.rb"
Expand Down
1 change: 1 addition & 0 deletions lib/rating.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
module Rating
end

require 'rating/config'
require 'rating/models/rating/extension'
require 'rating/models/rating/rate'
require 'rating/models/rating/rating'
Expand Down
25 changes: 25 additions & 0 deletions lib/rating/config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# frozen_string_literal: true

module Rating
module Config
module_function

def config
@config ||= begin
file_path = File.expand_path('config/rating.yml')

return {} unless File.exist?(file_path)

YAML.safe_load(File.read(file_path))['rating']
end
end

def rate_table
@rate_table ||= config[__method__.to_s] || 'rating_rates'
end

def rating_table
@rating_table ||= config[__method__.to_s] || 'rating_ratings'
end
end
end
16 changes: 14 additions & 2 deletions lib/rating/models/rating/extension.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,23 @@ def rated(scope: nil)
def rating(scope: nil)
rating_records.find_by scopeable: scope
end

def rating_warm_up(scoping: nil)
return Rating.find_or_create_by(resource: self) if scoping.blank?

[scoping].flatten.compact.map do |attribute|
next unless respond_to?(attribute)

[public_send(attribute)].flatten.compact.map do |object|
Rating.find_or_create_by! resource: self, scopeable: object
end
end.flatten.compact
end
end

module ClassMethods
def rating(as: nil)
after_create -> { Rating.find_or_create_by resource: self }, unless: -> { as == :author }
def rating(as: nil, scoping: nil)
after_create -> { rating_warm_up scoping: scoping }, unless: -> { as == :author }

has_many :rating_records,
as: :resource,
Expand Down
3 changes: 2 additions & 1 deletion lib/rating/models/rating/rate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

module Rating
class Rate < ActiveRecord::Base
self.table_name = 'rating_rates'
self.table_name_prefix = 'rating_'
self.table_name = ::Rating::Config.rate_table

after_save :update_rating

Expand Down
5 changes: 3 additions & 2 deletions lib/rating/models/rating/rating.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

module Rating
class Rating < ActiveRecord::Base
self.table_name = 'rating_ratings'
self.table_name_prefix = 'rating_'
self.table_name = ::Rating::Config.rating_table

belongs_to :resource, polymorphic: true
belongs_to :scopeable, polymorphic: true
Expand Down Expand Up @@ -100,7 +101,7 @@ def how_many_resource_received_votes_sql?(distinct:, scopeable:)
count = distinct ? 'COUNT(DISTINCT resource_id)' : 'COUNT(1)'

%((
SELECT #{count}
SELECT GREATEST(#{count}, 1)
FROM #{rate_table_name}
WHERE resource_type = :resource_type AND #{scope_type_query(scopeable)}
))
Expand Down
13 changes: 13 additions & 0 deletions spec/config/rate_table_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe Rating::Config, '.rate_table' do
context 'when rating.yml does not exist' do
it { expect(subject.rate_table).to eq 'rating_rates' }
end if ENV['CONFIG_ENABLED'] != 'true'

context 'when rating.yml exists' do
it { expect(subject.rate_table).to eq 'reviews' }
end if ENV['CONFIG_ENABLED'] == 'true'
end
13 changes: 13 additions & 0 deletions spec/config/rating_table_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe Rating::Config, '.rating_table' do
context 'when rating.yml does not exist' do
it { expect(subject.rating_table).to eq 'rating_ratings' }
end if ENV['CONFIG_ENABLED'] != 'true'

context 'when rating.yml exists' do
it { expect(subject.rating_table).to eq 'review_ratings' }
end if ENV['CONFIG_ENABLED'] == 'true'
end
5 changes: 5 additions & 0 deletions spec/factories/comment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

FactoryBot.define do
factory :comment
end
53 changes: 36 additions & 17 deletions spec/models/extension/after_create_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,46 @@

require 'rails_helper'

RSpec.describe Rating::Extension, ':after_create' do
context 'when :as is nil' do
let!(:article) { create :article }

it 'creates a rating record with zero values just to be easy to make the count' do
rating = Rating::Rating.find_by(resource: article)

expect(rating.average).to eq 0
expect(rating.estimate).to eq 0
expect(rating.resource).to eq article
expect(rating.scopeable).to eq nil
expect(rating.sum).to eq 0
expect(rating.total).to eq 0
RSpec.describe Rating::Extension, 'after_create' do
context 'when record is author' do
let!(:record) { build :author }

it 'does not warm up the cache' do
expect(record).not_to receive(:rating_warm_up)

record.save
end
end

context 'when :as is :author' do
let!(:author) { create :author }
context 'when record is not author' do
context 'when record has scoping' do
let!(:record) { build :article }

it 'warms up the cache' do
expect(record).to receive(:rating_warm_up).with(scoping: :categories)

record.save
end
end

context 'when record has no scoping' do
let!(:record) { build :comment }

it 'warms up the cache' do
expect(record).to receive(:rating_warm_up).with(scoping: nil)

record.save
end
end

context 'when update is made' do
let!(:record) { create :comment }

it 'does not warm up the cache' do
expect(record).not_to receive(:rating_warm_up)

it 'does not creates a rating record' do
expect(Rating::Rating.exists?(resource: author)).to eq false
record.save
end
end
end
end
115 changes: 115 additions & 0 deletions spec/models/extension/rating_warm_up_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe Rating::Extension, '.rating_warm_up' do
context 'when scoping is nil' do
context 'when update is made' do
let!(:record) { create :comment }
let!(:rating) { ::Rating::Rating.find_by resource: record }

it 'creates the cache' do
record.rating_warm_up scoping: nil

expect(::Rating::Rating.all).to eq [rating]
end

it 'returns the cached object' do
expect(record.rating_warm_up).to eq rating
end
end

context 'when record does not exist' do
let!(:record) { create :comment }

before { ::Rating::Rating.destroy_all }

it 'creates the cache' do
record.rating_warm_up scoping: nil

expect(::Rating::Rating.all.map(&:resource)).to eq [record]
end

it 'returns the cached object' do
expect(record.rating_warm_up).to eq ::Rating::Rating.last
end
end
end

context 'when scoping is not nil' do
context 'when update is made' do
let!(:category_1) { create :category }
let!(:category_2) { create :category }
let!(:record) { create :article, categories: [category_1, category_2] }

it 'creates the cache' do
record.rating_warm_up scoping: :categories

ratings = ::Rating::Rating.all

expect(ratings.map(&:scopeable)).to match_array [category_1, category_2]
expect(ratings.map(&:resource)).to match_array [record, record]
end

it 'returns the cached objects' do
expect(record.rating_warm_up(scoping: :categories)).to eq ::Rating::Rating.all
end
end

context 'when record does not exist' do
let!(:category_1) { create :category }
let!(:category_2) { create :category }
let!(:record) { create :article, categories: [category_1, category_2] }

before { ::Rating::Rating.destroy_all }

it 'creates the cache' do
record.rating_warm_up scoping: :categories

ratings = ::Rating::Rating.all

expect(ratings.map(&:scopeable)).to match_array [category_1, category_2]
expect(ratings.map(&:resource)).to match_array [record, record]
end

it 'returns the cached objects' do
expect(record.rating_warm_up(scoping: :categories)).to eq ::Rating::Rating.all
end
end

context 'when a non existent scoping is given' do
let!(:record) { create :article }

it 'returns an empty array' do
expect(record.rating_warm_up(scoping: :missing)).to eq []
end
end

context 'when scoping is given inside array' do
let!(:category) { create :category }
let!(:record) { create :article, categories: [category] }

it 'returns the cache' do
expect(record.rating_warm_up(scoping: [:categories])).to eq ::Rating::Rating.all
end
end

context 'when scoping is given inside multiple arrays' do
let!(:category) { create :category }
let!(:record) { create :article, categories: [category] }

it 'returns the cache' do
expect(record.rating_warm_up(scoping: [[:categories]])).to eq ::Rating::Rating.all
end
end

context 'when scoping is given with nil value together' do
let!(:category) { create :category }
let!(:record) { create :article, categories: [category] }

it 'returns the cache' do
expect(record.rating_warm_up(scoping: [[:categories, nil], nil])).to eq ::Rating::Rating.all
end
end
end
end
Loading

0 comments on commit 719a603

Please sign in to comment.