Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions app/controllers/api/experiments_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,20 @@

module Api
class ExperimentsController < ApplicationController
before_action :device_header
before_action :validate_header!

def index
if header_valid?
@experiments = Api::ExperimentService.call(@token)
else
render json: {}, status: :forbidden
end
@experiment = Api::ExperimentService.call(device_header)
end

private

def device_header
@token = request.headers['Device-Token']
def validate_header!
render(json: {}, status: :forbidden) unless device_header
end

def header_valid?
request.headers.key? 'Device-Token'
def device_header
@device_header ||= request.headers['Device-Token']
end
end
end
18 changes: 0 additions & 18 deletions app/models/experiment.rb
Original file line number Diff line number Diff line change
@@ -1,25 +1,7 @@
# frozen_string_literal: true

require 'distribution'

class Experiment < ApplicationRecord
validates :token, presence: true, uniqueness: true # rubocop:disable Rails/UniqueValidationWithoutIndex
validates :button_color, presence: true
validates :price, presence: true

def self.colors
@colors ||= Color.new
end

def self.prices
@prices ||= Price.new
end

def self.color
@colors.distribution
end

def self.price
@prices.distribution
end
end
39 changes: 10 additions & 29 deletions app/services/api/experiment_service.rb
Original file line number Diff line number Diff line change
@@ -1,41 +1,22 @@
# frozen_string_literal: true

require 'distribution'

module Api
class ExperimentService < ApplicationService
attr_reader :token, :color_distribution, :price_distribution

def initialize(token) # rubocop:disable Lint/MissingSuper: Call super to initialize state of the parent class.
@token = token
@color_distribution = Distribution::Color.new
@price_distribution = Distribution::Price.new
end

def call
default_values
attribute_color if query_to_db_valid?
attribute_price if query_to_db_valid?
experiment_params
@experiment = Experiment.create experiment_params
@experiments = Experiment.select(:button_color, :price).where(token: @token)
end

private

def default_values
Experiment.colors
Experiment.prices
end

def attribute_color
@button_color = Experiment.color
end

def attribute_price
@price = Experiment.price
end

def query_to_db_valid?
!Experiment.exists?(token: @token)
end

def experiment_params
@params = { token: @token, button_color: @button_color, price: @price }
Experiment.find_or_create_by(token: token) do |experiment|
experiment.button_color = color_distribution.next_value
experiment.price = price_distribution.next_value
end
end
end
end
4 changes: 2 additions & 2 deletions app/views/api/experiments/index.json.jbuilder
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# frozen_string_literal: true

json.experiments([{ value: @experiments.pluck(:button_color)[0], key: 'button_color' },
{ value: @experiments.pluck(:price)[0], key: 'price' }])
json.experiments([{ value: @experiment.button_color, key: 'button_color' },
{ value: @experiment.price, key: 'price' }])
64 changes: 33 additions & 31 deletions lib/distribution.rb
Original file line number Diff line number Diff line change
@@ -1,41 +1,43 @@
# frozen_string_literal: true

class Color
def initialize
@colors = []
end
class Distribution
class Color
def initialize
@colors = []
end

def distribution
@colors = %w[#FF0000 #00FF00 #0000FF] if @colors.empty?
@colors.shift
def next_value
@colors = %w[#FF0000 #00FF00 #0000FF] if @colors.empty?
@colors.shift
end
end
end

class Price
def initialize
@probability = [0.75, 0.1, 0.1, 0.05]
@prices = []
@counter = 0
end
class Price
def initialize
@probability = [0.75, 0.1, 0.1, 0.05]
@prices = []
@counter = 0
end

def distribution
@counter += 1
price1 = (@counter * @probability[0]).round
price2 = (@counter * @probability[1]).round
price3 = (@counter * @probability[2]).round
price4 = (@counter * @probability[3]).round
@prices << calculation_price(price1, price2, price3, price4)
@prices.last
end
def next_value
@counter += 1
price1 = (@counter * @probability[0]).round
price2 = (@counter * @probability[1]).round
price3 = (@counter * @probability[2]).round
price4 = (@counter * @probability[3]).round
@prices << calculation_price(price1, price2, price3, price4)
@prices.last
end

def calculation_price(price1, price2, price3, price4)
if @prices.count('10') < price1 then '10'
elsif @prices.count('20') < price2 then '20'
elsif @prices.count('5') < price3 then '5'
elsif @prices.count('50') < price4 then '50'
# rubocop:disable Lint/DuplicateBranch: Duplicate branch body detected.
else '10' # This is necessary logic
# rubocop:enable Lint/DuplicateBranch: Duplicate branch body detected.
def calculation_price(price1, price2, price3, price4)
if @prices.count('10') < price1 then '10'
elsif @prices.count('20') < price2 then '20'
elsif @prices.count('5') < price3 then '5'
elsif @prices.count('50') < price4 then '50'
# rubocop:disable Lint/DuplicateBranch: Duplicate branch body detected.
else '10' # This is necessary logic
# rubocop:enable Lint/DuplicateBranch: Duplicate branch body detected.
end
end
end
end