diff --git a/app/controllers/api/experiments_controller.rb b/app/controllers/api/experiments_controller.rb index 48fab15..f621bb6 100644 --- a/app/controllers/api/experiments_controller.rb +++ b/app/controllers/api/experiments_controller.rb @@ -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 diff --git a/app/models/experiment.rb b/app/models/experiment.rb index 0775225..1bea16c 100644 --- a/app/models/experiment.rb +++ b/app/models/experiment.rb @@ -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 diff --git a/app/services/api/experiment_service.rb b/app/services/api/experiment_service.rb index 4307315..0ca0588 100644 --- a/app/services/api/experiment_service.rb +++ b/app/services/api/experiment_service.rb @@ -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 diff --git a/app/views/api/experiments/index.json.jbuilder b/app/views/api/experiments/index.json.jbuilder index 55f9a07..932ff21 100644 --- a/app/views/api/experiments/index.json.jbuilder +++ b/app/views/api/experiments/index.json.jbuilder @@ -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' }]) diff --git a/lib/distribution.rb b/lib/distribution.rb index a297eac..59f7581 100644 --- a/lib/distribution.rb +++ b/lib/distribution.rb @@ -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