diff --git a/.rubocop.yml b/.rubocop.yml index 24a44ec..be599a8 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -57,6 +57,11 @@ Style/FrozenStringLiteralComment: Style/PercentLiteralDelimiters: Enabled: false +# Until today I have never needed to know created_at and updated_at. ¯\_(ツ)_/¯ +# Let's only add them when we have a good reason. +Rails/CreateTableWithTimestamps: + Enabled: false + # Because warning asked to add these... Lint/RaiseException: Enabled: true @@ -68,3 +73,5 @@ Style/HashTransformKeys: Enabled: true Style/HashTransformValues: Enabled: true + + diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index daed0b2..8153e6a 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,7 +1,12 @@ class ApplicationController < ActionController::API - # To give all controllers the tools to be JSON API spec compliant. + # Give all controllers the methods for handling requests per JSON API spec. include JsonApiController - # To allow controllers to set and read cookies. + # Allow controllers to set and read cookies. include ActionController::Cookies + + # Allow all controllers to log with a shorthand. + def log + Rails.logger + end end diff --git a/app/controllers/concerns/json_api_controller.rb b/app/controllers/concerns/json_api_controller.rb index ad3b339..69d8fe6 100644 --- a/app/controllers/concerns/json_api_controller.rb +++ b/app/controllers/concerns/json_api_controller.rb @@ -391,8 +391,13 @@ def forbidden_filters # allow_create # end # - def allow_create - resource = model_class.new(attributes_and_relationships) + def allow_create(controller_attributes) + hash = strong_attributes + .merge(strong_relationships) + .merge(controller_attributes) + + resource = model_class.new(hash) + if resource.save! json = serializer_class.new(resource).serializable_hash.to_json render status: 201, json: json diff --git a/app/controllers/v1/admin/client_side_renders_controller.rb b/app/controllers/v1/admin/client_side_renders_controller.rb new file mode 100644 index 0000000..23f1beb --- /dev/null +++ b/app/controllers/v1/admin/client_side_renders_controller.rb @@ -0,0 +1,35 @@ +module V1 + module Admin + class ClientSideRendersController < ApplicationController + def index + allow_index + end + + def show + allow_show + end + + def create + forbidden + end + + def update + forbidden + end + + def destroy + forbidden + end + + private + + def model_class + ClientSideRender + end + + def serializer_class + V1::Admin::ClientSideRenderSerializer + end + end + end +end diff --git a/app/controllers/v1/admin/page_views_controller.rb b/app/controllers/v1/admin/page_views_controller.rb new file mode 100644 index 0000000..ee13891 --- /dev/null +++ b/app/controllers/v1/admin/page_views_controller.rb @@ -0,0 +1,35 @@ +module V1 + module Admin + class PageViewsController < ApplicationController + def index + allow_index + end + + def show + allow_show + end + + def create + forbidden + end + + def update + forbidden + end + + def destroy + forbidden + end + + private + + def model_class + PageView + end + + def serializer_class + V1::Admin::PageViewSerializer + end + end + end +end diff --git a/app/controllers/v1/admin/server_side_renders_controller.rb b/app/controllers/v1/admin/server_side_renders_controller.rb new file mode 100644 index 0000000..7e36558 --- /dev/null +++ b/app/controllers/v1/admin/server_side_renders_controller.rb @@ -0,0 +1,35 @@ +module V1 + module Admin + class ServerSideRendersController < ApplicationController + def index + allow_index + end + + def show + allow_show + end + + def create + forbidden + end + + def update + forbidden + end + + def destroy + forbidden + end + + private + + def model_class + ServerSideRender + end + + def serializer_class + V1::Admin::ServerSideRenderSerializer + end + end + end +end diff --git a/app/controllers/v1/admin/visits_controller.rb b/app/controllers/v1/admin/visits_controller.rb new file mode 100644 index 0000000..bb4a53d --- /dev/null +++ b/app/controllers/v1/admin/visits_controller.rb @@ -0,0 +1,49 @@ +module V1 + module Admin + class VisitsController < ApplicationController + def index + allow_index + end + + def show + allow_show + end + + def create + forbidden + end + + def update + forbidden + end + + def destroy + forbidden + end + + private + + def model_class + Visit + end + + def serializer_class + V1::Admin::VisitSerializer + end + + def permitted_filters + %i[ + host + ] + end + + def permitted_includes + %i[ + server_side_renders + client_side_renders + user + ] + end + end + end +end diff --git a/app/controllers/v1/public/client_side_renders_controller.rb b/app/controllers/v1/public/client_side_renders_controller.rb new file mode 100644 index 0000000..fd34029 --- /dev/null +++ b/app/controllers/v1/public/client_side_renders_controller.rb @@ -0,0 +1,61 @@ +module V1 + module Public + class ClientSideRendersController < ApplicationController + def index + forbidden + end + + def show + forbidden + end + + def create + allow_create( + { + id: params[:data][:id], + ip: request.remote_ip + } + ) + end + + def update + forbidden + end + + def destroy + forbidden + end + + private + + def model_class + ClientSideRender + end + + def serializer_class + V1::Public::ClientSideRenderSerializer + end + + def creatable_attributes + %i[ + host + path + referrer + user_agent + viewport_width + viewport_height + server_side_render_id + browser_session_id + user_id + ] + end + + def creatable_relationships + %[ + visit + user + ] + end + end + end +end diff --git a/app/controllers/v1/public/page_views_controller.rb b/app/controllers/v1/public/page_views_controller.rb new file mode 100644 index 0000000..c0e472d --- /dev/null +++ b/app/controllers/v1/public/page_views_controller.rb @@ -0,0 +1,35 @@ +module V1 + module Public + class PageViewsController < ApplicationController + def index + allow_index + end + + def show + allow_show + end + + def create + forbidden + end + + def update + forbidden + end + + def destroy + forbidden + end + + private + + def model_class + PageView + end + + def serializer_class + V1::Public::PageViewSerializer + end + end + end +end diff --git a/app/controllers/v1/public/server_side_renders_controller.rb b/app/controllers/v1/public/server_side_renders_controller.rb new file mode 100644 index 0000000..270c4c1 --- /dev/null +++ b/app/controllers/v1/public/server_side_renders_controller.rb @@ -0,0 +1,55 @@ +module V1 + module Public + class ServerSideRendersController < ApplicationController + def index + forbidden + end + + def show + forbidden + end + + def create + allow_create( + { + id: params[:data][:id], + ip: request.remote_ip + } + ) + end + + def update + forbidden + end + + def destroy + forbidden + end + + private + + def model_class + ServerSideRender + end + + def serializer_class + V1::Public::ServerSideRenderSerializer + end + + def creatable_attributes + %i[ + host + path + referrer + user_agent + ] + end + + def creatable_relationships + %[ + visit + ] + end + end + end +end diff --git a/app/controllers/v1/public_controller.rb b/app/controllers/v1/public_controller.rb index fae6bb1..4ebdff7 100644 --- a/app/controllers/v1/public_controller.rb +++ b/app/controllers/v1/public_controller.rb @@ -1,4 +1,33 @@ module V1 class PublicController < ApplicationController + before_action :create_visit + + private + + def create_visit + id = request.headers['Visit-ID'] + + return nil if id.nil? + + record = Visit.find_by(id: id) + + if record.nil? + Visit.create!( + id: id, + start_time: DateTime.current, + user_agent_ssr: request.headers['SSR-User-Agent'] + ) + log.debug '🌈 visit created' + elsif !record.user_agent? || !request.browser_width + Visit.update( + user_agent: request.user_agent, + browser_width: request.headers['Browser-Width'], + browser_height: request.headers['Browser-Height'] + ) + log.debug '🌳 visit updated' + else + log.debug '❌ doing nothing' + end + end end end diff --git a/app/models/client_side_render.rb b/app/models/client_side_render.rb new file mode 100644 index 0000000..aabbd81 --- /dev/null +++ b/app/models/client_side_render.rb @@ -0,0 +1,24 @@ +# == Schema Information +# +# Table name: client_side_renders +# +# id :uuid not null, primary key +# host :string +# ip :string +# path :string +# referrer :string +# user_agent :string +# viewport_height :integer +# viewport_width :integer +# created_at :datetime not null +# updated_at :datetime not null +# browser_session_id :uuid +# server_side_render_id :uuid +# user_id :uuid +# visit_id :uuid +# +class ClientSideRender < ApplicationRecord + belongs_to :server_side_render, optional: true + belongs_to :visit, optional: true + belongs_to :user, optional: true +end diff --git a/app/models/page_view.rb b/app/models/page_view.rb new file mode 100644 index 0000000..3bfae68 --- /dev/null +++ b/app/models/page_view.rb @@ -0,0 +1,13 @@ +# == Schema Information +# +# Table name: page_views +# +# id :uuid not null, primary key +# path :string +# created_at :datetime not null +# updated_at :datetime not null +# browser_session_id :uuid +# +class PageView < ApplicationRecord + belongs_to :visit +end diff --git a/app/models/server_side_render.rb b/app/models/server_side_render.rb new file mode 100644 index 0000000..792d2c0 --- /dev/null +++ b/app/models/server_side_render.rb @@ -0,0 +1,19 @@ +# == Schema Information +# +# Table name: server_side_renders +# +# id :uuid not null, primary key +# host :string +# ip :string +# path :string +# referrer :string +# user_agent :string +# created_at :datetime not null +# updated_at :datetime not null +# visit_id :uuid +# +class ServerSideRender < ApplicationRecord + belongs_to :visit, optional: true + + has_one :client_side_render +end diff --git a/app/models/visit.rb b/app/models/visit.rb new file mode 100644 index 0000000..b3c4dea --- /dev/null +++ b/app/models/visit.rb @@ -0,0 +1,31 @@ +# == Schema Information +# +# Table name: visits +# +# id :uuid not null, primary key +# first_seen :datetime +# host :string +# ip :string +# ip_isp :string +# is_bot :boolean +# is_interflux :boolean +# last_seen :datetime +# path :string +# referrer :string +# user_agent :string +# viewport_height :integer +# viewport_width :integer +# created_at :datetime not null +# updated_at :datetime not null +# browser_session_id :uuid +# ip_country_id :string +# user_id :uuid +# +class Visit < ApplicationRecord + belongs_to :user, optional: true + belongs_to :ip_country, optional: true, class_name: 'Country' + + has_many :server_side_renders, dependent: :restrict_with_exception + has_many :client_side_renders, dependent: :restrict_with_exception + has_many :page_views, dependent: :restrict_with_exception +end diff --git a/app/serializers/v1/admin/client_side_render_serializer.rb b/app/serializers/v1/admin/client_side_render_serializer.rb new file mode 100644 index 0000000..d27acf8 --- /dev/null +++ b/app/serializers/v1/admin/client_side_render_serializer.rb @@ -0,0 +1,19 @@ +module V1 + module Admin + class ClientSideRenderSerializer < ApplicationSerializer + attributes :host, + :path, + :referrer, + :user_agent, + :ip, + :viewport_width, + :viewport_height, + :created_at, + :browser_session_id + + belongs_to :server_side_render + belongs_to :user + belongs_to :visit + end + end +end diff --git a/app/serializers/v1/admin/page_view_serializer.rb b/app/serializers/v1/admin/page_view_serializer.rb new file mode 100644 index 0000000..d85b637 --- /dev/null +++ b/app/serializers/v1/admin/page_view_serializer.rb @@ -0,0 +1,10 @@ +module V1 + module Admin + class PageViewSerializer < ApplicationSerializer + attributes :path, + :created_at + + belongs_to :Visit + end + end +end diff --git a/app/serializers/v1/admin/server_side_render_serializer.rb b/app/serializers/v1/admin/server_side_render_serializer.rb new file mode 100644 index 0000000..c11c6f1 --- /dev/null +++ b/app/serializers/v1/admin/server_side_render_serializer.rb @@ -0,0 +1,14 @@ +module V1 + module Admin + class ServerSideRenderSerializer < ApplicationSerializer + attributes :host, + :path, + :referrer, + :user_agent, + :ip, + :created_at + + belongs_to :visit + end + end +end diff --git a/app/serializers/v1/admin/visit_serializer.rb b/app/serializers/v1/admin/visit_serializer.rb new file mode 100644 index 0000000..248f896 --- /dev/null +++ b/app/serializers/v1/admin/visit_serializer.rb @@ -0,0 +1,25 @@ +module V1 + module Admin + class VisitSerializer < ApplicationSerializer + attributes :host, + :referrer, + :user_agent, + :ip, + :ip_isp, + :viewport_width, + :viewport_height, + :is_interflux, + :is_bot, + :first_seen, + :last_seen, + :browser_session_id + + belongs_to :user + belongs_to :ip_country, record_type: :country, serializer: :country + + has_many :server_side_renders + has_many :client_side_renders + has_many :page_views + end + end +end diff --git a/app/serializers/v1/public/client_side_render_serializer.rb b/app/serializers/v1/public/client_side_render_serializer.rb new file mode 100644 index 0000000..8c40b1f --- /dev/null +++ b/app/serializers/v1/public/client_side_render_serializer.rb @@ -0,0 +1,7 @@ +module V1 + module Public + class ClientSideRenderSerializer < ApplicationSerializer + # Return nothing apart from the ID and type. + end + end +end diff --git a/app/serializers/v1/public/page_view_serializer.rb b/app/serializers/v1/public/page_view_serializer.rb new file mode 100644 index 0000000..85f60fc --- /dev/null +++ b/app/serializers/v1/public/page_view_serializer.rb @@ -0,0 +1,7 @@ +module V1 + module Public + class PageViewSerializer < ApplicationSerializer + # Return nothing apart from the ID and type. + end + end +end diff --git a/app/serializers/v1/public/server_side_render_serializer.rb b/app/serializers/v1/public/server_side_render_serializer.rb new file mode 100644 index 0000000..3bfdf36 --- /dev/null +++ b/app/serializers/v1/public/server_side_render_serializer.rb @@ -0,0 +1,7 @@ +module V1 + module Public + class ServerSideRenderSerializer < ApplicationSerializer + # Return nothing apart from the ID and type. + end + end +end diff --git a/config/environments/development.rb b/config/environments/development.rb index b67108a..f601370 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -60,7 +60,7 @@ # When developing, do not log. Instead output everything in terminal. config.logger = Logger.new($stdout) - config.log_level = :debug + config.log_level = :info # config.logger.datetime_format = '%Y-%m-%d %H:%M:%S' config.logger.formatter = proc do |severity, _datetime, _progname, msg| "#{severity} #{msg}\n" diff --git a/config/routes.rb b/config/routes.rb index 77f001d..f27e0f6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -9,14 +9,17 @@ # such as scrapers and bots, to read from them. # # Used by: - # https://app.interflux.com - # https://www.interflux.com - # https://lmpa.interflux.com + # https://interflux.com + # https://interflux.de + # https://interflux.fr + # https://interflux.es + # https://interflux.group + # https://lmpa-q.com # - namespace :public do resources :article_categories, path: '/article-categories' resources :articles + resources :client_side_renders, path: '/client-side-renders' resources :companies resources :company_markets, path: '/company-markets' resources :countries @@ -27,12 +30,14 @@ resources :images resources :languages resources :leads + resources :page_views, path: '/page-views' resources :permalinks resources :product_families, path: '/product-families' resources :product_qualities, path: '/product-qualities' resources :product_uses, path: '/product-uses' resources :products resources :qualities + resources :server_side_renders, path: '/server-side-renders' resources :sessions resources :simulation_requests, path: '/simulation-requests' resources :translations @@ -56,6 +61,7 @@ resources :article_categories, path: '/article-categories' resources :articles resources :cdn_files, path: '/cdn-files' + resources :client_side_renders, path: '/client-side-renders' resources :companies resources :company_markets, path: '/company-markets' resources :company_members, path: '/company-members' @@ -67,6 +73,7 @@ resources :images resources :languages resources :leads + resources :page_views, path: '/page-views' resources :people resources :permalinks resources :person_images, path: '/person-images' @@ -75,17 +82,19 @@ resources :product_family_images, path: '/product-family-images' resources :product_features, path: '/product-features' resources :product_images, path: '/product-images' - resources :product_videos, path: '/product-videos' resources :product_qualities, path: '/product-qualities' resources :product_uses, path: '/product-uses' + resources :product_videos, path: '/product-videos' resources :products, path: '/products' resources :qualities + resources :server_side_renders, path: '/server-side-renders' resources :sessions resources :translations resources :use_images, path: '/use-images' resources :users resources :uses resources :videos + resources :visits resources :webinar_attendees, path: '/webinar-attendees' resources :webinar_images, path: '/webinar-images' resources :webinar_invitees, path: '/webinar-invitees' diff --git a/db/migrate/20240210021834_create_server_side_renders.rb b/db/migrate/20240210021834_create_server_side_renders.rb new file mode 100644 index 0000000..905f6b0 --- /dev/null +++ b/db/migrate/20240210021834_create_server_side_renders.rb @@ -0,0 +1,15 @@ +class CreateServerSideRenders < ActiveRecord::Migration[6.1] + def change + create_table :server_side_renders, id: :uuid do |t| + t.string :host + t.string :path + t.string :referrer + t.string :user_agent + t.string :ip + + t.uuid :visit_id + + t.timestamps + end + end +end diff --git a/db/migrate/20240210021840_create_client_side_renders.rb b/db/migrate/20240210021840_create_client_side_renders.rb new file mode 100644 index 0000000..ba950b6 --- /dev/null +++ b/db/migrate/20240210021840_create_client_side_renders.rb @@ -0,0 +1,21 @@ +class CreateClientSideRenders < ActiveRecord::Migration[6.1] + def change + create_table :client_side_renders, id: :uuid do |t| + t.string :host + t.string :path + t.string :referrer + t.string :user_agent + t.string :ip + + t.integer :viewport_width + t.integer :viewport_height + + t.uuid :server_side_render_id + t.uuid :browser_session_id + t.uuid :user_id + t.uuid :visit_id + + t.timestamps + end + end +end diff --git a/db/migrate/20240210021852_create_visits.rb b/db/migrate/20240210021852_create_visits.rb new file mode 100644 index 0000000..0b3da81 --- /dev/null +++ b/db/migrate/20240210021852_create_visits.rb @@ -0,0 +1,27 @@ +class CreateVisits < ActiveRecord::Migration[6.1] + def change + create_table :visits, id: :uuid do |t| + t.string :host + t.string :path + t.string :referrer + t.string :user_agent + t.string :ip + t.string :ip_isp + t.string :ip_country_id + + t.integer :viewport_width + t.integer :viewport_height + + t.boolean :is_interflux + t.boolean :is_bot + + t.uuid :browser_session_id + t.uuid :user_id + + t.datetime :first_seen + t.datetime :last_seen + + t.timestamps + end + end +end diff --git a/db/migrate/20240210021903_create_page_views.rb b/db/migrate/20240210021903_create_page_views.rb new file mode 100644 index 0000000..4597f52 --- /dev/null +++ b/db/migrate/20240210021903_create_page_views.rb @@ -0,0 +1,11 @@ +class CreatePageViews < ActiveRecord::Migration[6.1] + def change + create_table :page_views, id: :uuid do |t| + t.string :path + + t.uuid :browser_session_id + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 775faf9..de92aef 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2024_01_27_091511) do +ActiveRecord::Schema.define(version: 2024_02_10_021903) do # These are extensions that must be enabled in order to support this database enable_extension "pgcrypto" @@ -60,6 +60,22 @@ t.index ["path"], name: "index_cdn_files_on_path" end + create_table "client_side_renders", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.string "host" + t.string "path" + t.string "referrer" + t.string "user_agent" + t.string "ip" + t.integer "viewport_width" + t.integer "viewport_height" + t.uuid "server_side_render_id" + t.uuid "browser_session_id" + t.uuid "user_id" + t.uuid "visit_id" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + end + create_table "companies", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "slug" t.string "business_name" @@ -270,6 +286,13 @@ t.index ["ip_country_id"], name: "index_leads_on_ip_country_id" end + create_table "page_views", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.string "path" + t.uuid "browser_session_id" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + end + create_table "people", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.datetime "created_at", null: false t.datetime "updated_at", null: false @@ -452,6 +475,17 @@ t.string "image_id" end + create_table "server_side_renders", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.string "host" + t.string "path" + t.string "referrer" + t.string "user_agent" + t.string "ip" + t.uuid "visit_id" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + end + create_table "sessions", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "href" t.string "referrer" @@ -553,6 +587,26 @@ t.datetime "updated_at", precision: 6, null: false end + create_table "visits", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.string "host" + t.string "path" + t.string "referrer" + t.string "user_agent" + t.string "ip" + t.string "ip_isp" + t.string "ip_country_id" + t.integer "viewport_width" + t.integer "viewport_height" + t.boolean "is_interflux" + t.boolean "is_bot" + t.uuid "browser_session_id" + t.uuid "user_id" + t.datetime "first_seen" + t.datetime "last_seen" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + end + create_table "webinar_attendees", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.uuid "webinar_id" t.uuid "person_id" diff --git a/lib/tasks/visits.rake b/lib/tasks/visits.rake new file mode 100644 index 0000000..748d309 --- /dev/null +++ b/lib/tasks/visits.rake @@ -0,0 +1,119 @@ +namespace :visits do + task process: :environment do + log.info 'visits:process ⛵️' + + # For reference: + # ClientSideRender.joins(:visit) + # ClientSideRender.where.missing(:visit) + # ... are opposites. + + browser_sessions = ClientSideRender.where.missing(:visit).pluck(:browser_session_id).uniq + + browser_sessions.each do |browser_session| + csrs = ClientSideRender.where(browser_session_id: browser_session).order('created_at ASC') + + # The host, user agent and IP should be unique across the entire browser session. + + hosts = csrs.pluck(:host).uniq + user_agents = csrs.pluck(:user_agent).uniq + ips = csrs.pluck(:ip).uniq + + if hosts.count != 1 + log.warn "❌ 1 | #{browser_session}" + next + end + + if user_agents.count != 1 + log.warn "❌ 2 | #{browser_session}" + next + end + + if ips.count != 1 + log.warn "❌ 3 | #{browser_session}" + next + end + + record = Visit.create( + browser_session_id: browser_session, + + host: hosts.first, + path: csrs.first.path, + referrer: csrs.first.referrer, + user_agent: user_agents.first, + + ip: ips.first, + # ip_isp: nil, # TODO + # ip_country_id: nil, # TODO + + viewport_width: csrs.first.viewport_width, + viewport_height: csrs.first.viewport_height, + + # is_interflux: false, # TODO + # is_bot: false, # TODO + + first_seen: csrs.first.created_at + # last_seen: nil # TODO + # user_id: nil # TODO + ) + + log.info "✅ created Visit #{record.id}" + + csrs.each do |csr| + csr.update(visit: record) + + ssr = csr.server_side_render + + if ssr.nil? + log.warn '❌ no SSR' + log.warn csr.id + next + end + + ssr.update(visit: record) + + log.info '✅ - updated CSR and SSR' + + if csr.path != ssr.path + log.warn '❌ path not identical' + log.warn csr.id + log.warn csr.path + log.warn ssr.path + end + + if csr.host != ssr.host + log.warn '❌ host not identical' + log.warn csr.id + log.warn csr.host + log.warn ssr.host + end + + if csr.referrer != ssr.referrer + log.warn '❌ referrer not identical' + log.warn csr.id + log.warn csr.referrer + log.warn ssr.referrer + end + + if csr.user_agent != ssr.user_agent + log.warn '❌ UA not identical' + log.warn csr.id + log.warn csr.user_agent + log.warn ssr.user_agent + end + + next unless csr.ip != ssr.ip + + log.warn '❌ IP not identical' + log.warn csr.id + log.warn csr.ip + log.warn ssr.ip + end + end + + log.info 'visits:process ✅' + end + + def log + Rails.logger + end +end