Init dump

This commit is contained in:
Jason Jordan
2025-11-24 08:22:44 -05:00
parent d48bb96791
commit 3fbece7da6
73 changed files with 1747 additions and 121 deletions
+3
View File
@@ -72,3 +72,6 @@ yarn-debug.log*
/config/master.key /config/master.key
.DS_Store .DS_Store
/app/assets/builds/*
!/app/assets/builds/.keep
+9
View File
@@ -0,0 +1,9 @@
FROM mcr.microsoft.com/mssql/server:2017-latest
ENV ACCEPT_EULA=Y
ENV MSSQL_SA_PASSWORD=Br1tt0nPassw0rd
ENV MSSQL_PID=Developer
COPY init.sql .
COPY ./bin/dbentrypoint.sh .
EXPOSE 1434
CMD /bin/bash dbentrypoint.sh
+12 -7
View File
@@ -12,9 +12,6 @@ gem "rails", "~> 7.2"
# The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails]
gem "sprockets-rails" gem "sprockets-rails"
# Use postgresql as the database for Active Record
gem "pg", "~> 1.5"
# Use the Puma web server [https://github.com/puma/puma] # Use the Puma web server [https://github.com/puma/puma]
gem "puma", "~> 6.5" gem "puma", "~> 6.5"
@@ -31,7 +28,7 @@ gem "stimulus-rails"
gem "jbuilder" gem "jbuilder"
# Use Redis adapter to run Action Cable in production # Use Redis adapter to run Action Cable in production
gem "redis", "~> 5.3" # gem "redis", "~> 5.3"
# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] # Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis]
# gem "kredis" # gem "kredis"
@@ -40,17 +37,17 @@ gem "redis", "~> 5.3"
# gem "bcrypt", "~> 3.1.7" # gem "bcrypt", "~> 3.1.7"
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ windows jruby ] gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ]
# Reduces boot times through caching; required in config/boot.rb # Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", require: false gem "bootsnap", require: false
# Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images]
gem "image_processing", "~> 1.2" # gem "image_processing", "~> 1.2"
group :development, :test do group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude" # gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"
# Static analysis for security vulnerabilities [https://brakemanscanner.org/] # Static analysis for security vulnerabilities [https://brakemanscanner.org/]
gem "brakeman", require: false gem "brakeman", require: false
@@ -70,6 +67,8 @@ group :development do
# Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler]
gem "rack-mini-profiler" gem "rack-mini-profiler"
gem "pry-rails"
end end
group :test do group :test do
@@ -77,3 +76,9 @@ group :test do
gem "capybara" gem "capybara"
gem "selenium-webdriver" gem "selenium-webdriver"
end end
gem 'activerecord-sqlserver-adapter'
gem 'tiny_tds'
gem 'devise'
gem 'pundit'
gem "tailwindcss-rails"
+51 -34
View File
@@ -56,6 +56,9 @@ GEM
activemodel (= 7.2.3) activemodel (= 7.2.3)
activesupport (= 7.2.3) activesupport (= 7.2.3)
timeout (>= 0.4.0) timeout (>= 0.4.0)
activerecord-sqlserver-adapter (7.2.8)
activerecord (~> 7.2.0)
tiny_tds
activestorage (7.2.3) activestorage (7.2.3)
actionpack (= 7.2.3) actionpack (= 7.2.3)
activejob (= 7.2.3) activejob (= 7.2.3)
@@ -78,6 +81,7 @@ GEM
public_suffix (>= 2.0.2, < 7.0) public_suffix (>= 2.0.2, < 7.0)
ast (2.4.3) ast (2.4.3)
base64 (0.3.0) base64 (0.3.0)
bcrypt (3.1.20)
benchmark (0.5.0) benchmark (0.5.0)
bigdecimal (3.3.1) bigdecimal (3.3.1)
bindex (0.8.1) bindex (0.8.1)
@@ -99,32 +103,25 @@ GEM
regexp_parser (>= 1.5, < 3.0) regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2) xpath (~> 3.2)
cgi (0.5.0) cgi (0.5.0)
coderay (1.1.3)
concurrent-ruby (1.3.5) concurrent-ruby (1.3.5)
connection_pool (2.5.4) connection_pool (2.5.4)
crass (1.0.6) crass (1.0.6)
date (3.5.0) date (3.5.0)
debug (1.11.0) devise (4.9.4)
irb (~> 1.10) bcrypt (~> 3.0)
reline (>= 0.3.8) orm_adapter (~> 0.1)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
diff-lcs (1.6.2) diff-lcs (1.6.2)
drb (2.2.3) drb (2.2.3)
erb (5.1.3) erb (5.1.3)
erubi (1.13.1) erubi (1.13.1)
ffi (1.17.2-aarch64-linux-gnu)
ffi (1.17.2-aarch64-linux-musl)
ffi (1.17.2-arm-linux-gnu)
ffi (1.17.2-arm-linux-musl)
ffi (1.17.2-arm64-darwin)
ffi (1.17.2-x86_64-darwin)
ffi (1.17.2-x86_64-linux-gnu)
ffi (1.17.2-x86_64-linux-musl)
globalid (1.3.0) globalid (1.3.0)
activesupport (>= 6.1) activesupport (>= 6.1)
i18n (1.14.7) i18n (1.14.7)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
image_processing (1.14.0)
mini_magick (>= 4.9.5, < 6)
ruby-vips (>= 2.0.17, < 3)
importmap-rails (2.2.2) importmap-rails (2.2.2)
actionpack (>= 6.0.0) actionpack (>= 6.0.0)
activesupport (>= 6.0.0) activesupport (>= 6.0.0)
@@ -152,8 +149,7 @@ GEM
net-smtp net-smtp
marcel (1.1.0) marcel (1.1.0)
matrix (0.4.3) matrix (0.4.3)
mini_magick (5.3.1) method_source (1.1.0)
logger
mini_mime (1.1.5) mini_mime (1.1.5)
minitest (5.26.0) minitest (5.26.0)
msgpack (1.8.0) msgpack (1.8.0)
@@ -183,27 +179,28 @@ GEM
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.18.10-x86_64-linux-musl) nokogiri (1.18.10-x86_64-linux-musl)
racc (~> 1.4) racc (~> 1.4)
orm_adapter (0.5.0)
parallel (1.27.0) parallel (1.27.0)
parser (3.3.10.0) parser (3.3.10.0)
ast (~> 2.4.1) ast (~> 2.4.1)
racc racc
pg (1.6.2)
pg (1.6.2-aarch64-linux)
pg (1.6.2-aarch64-linux-musl)
pg (1.6.2-arm64-darwin)
pg (1.6.2-x86_64-darwin)
pg (1.6.2-x86_64-linux)
pg (1.6.2-x86_64-linux-musl)
pp (0.6.3) pp (0.6.3)
prettyprint prettyprint
prettyprint (0.2.0) prettyprint (0.2.0)
prism (1.6.0) prism (1.6.0)
pry (0.15.2)
coderay (~> 1.1)
method_source (~> 1.0)
pry-rails (0.3.11)
pry (>= 0.13.0)
psych (5.2.6) psych (5.2.6)
date date
stringio stringio
public_suffix (6.0.2) public_suffix (6.0.2)
puma (6.6.1) puma (6.6.1)
nio4r (~> 2.0) nio4r (~> 2.0)
pundit (2.5.2)
activesupport (>= 3.0.0)
racc (1.8.1) racc (1.8.1)
rack (3.2.4) rack (3.2.4)
rack-mini-profiler (4.0.1) rack-mini-profiler (4.0.1)
@@ -252,13 +249,12 @@ GEM
erb erb
psych (>= 4.0.0) psych (>= 4.0.0)
tsort tsort
redis (5.4.1)
redis-client (>= 0.22.0)
redis-client (0.26.1)
connection_pool
regexp_parser (2.11.3) regexp_parser (2.11.3)
reline (0.6.2) reline (0.6.2)
io-console (~> 0.5) io-console (~> 0.5)
responders (3.2.0)
actionpack (>= 7.0)
railties (>= 7.0)
rexml (3.4.4) rexml (3.4.4)
rspec-core (3.13.6) rspec-core (3.13.6)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
@@ -309,9 +305,6 @@ GEM
lint_roller (~> 1.1) lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1) rubocop (~> 1.72, >= 1.72.1)
ruby-progressbar (1.13.0) ruby-progressbar (1.13.0)
ruby-vips (2.2.5)
ffi (~> 1.12)
logger
rubyzip (3.2.2) rubyzip (3.2.2)
securerandom (0.4.1) securerandom (0.4.1)
selenium-webdriver (4.38.0) selenium-webdriver (4.38.0)
@@ -331,8 +324,28 @@ GEM
stimulus-rails (1.3.4) stimulus-rails (1.3.4)
railties (>= 6.0.0) railties (>= 6.0.0)
stringio (3.1.7) stringio (3.1.7)
tailwindcss-rails (4.4.0)
railties (>= 7.0.0)
tailwindcss-ruby (~> 4.0)
tailwindcss-ruby (4.1.16)
tailwindcss-ruby (4.1.16-aarch64-linux-gnu)
tailwindcss-ruby (4.1.16-aarch64-linux-musl)
tailwindcss-ruby (4.1.16-arm64-darwin)
tailwindcss-ruby (4.1.16-x86_64-darwin)
tailwindcss-ruby (4.1.16-x86_64-linux-gnu)
tailwindcss-ruby (4.1.16-x86_64-linux-musl)
thor (1.4.0) thor (1.4.0)
timeout (0.4.4) timeout (0.4.4)
tiny_tds (3.3.0)
bigdecimal (~> 3)
tiny_tds (3.3.0-aarch64-linux-gnu)
bigdecimal (~> 3)
tiny_tds (3.3.0-aarch64-linux-musl)
bigdecimal (~> 3)
tiny_tds (3.3.0-x86_64-linux-gnu)
bigdecimal (~> 3)
tiny_tds (3.3.0-x86_64-linux-musl)
bigdecimal (~> 3)
tsort (0.2.0) tsort (0.2.0)
turbo-rails (2.0.20) turbo-rails (2.0.20)
actionpack (>= 7.1.0) actionpack (>= 7.1.0)
@@ -343,6 +356,8 @@ GEM
unicode-emoji (~> 4.1) unicode-emoji (~> 4.1)
unicode-emoji (4.1.0) unicode-emoji (4.1.0)
useragent (0.16.11) useragent (0.16.11)
warden (1.2.9)
rack (>= 2.0.9)
web-console (4.2.1) web-console (4.2.1)
actionview (>= 6.0.0) actionview (>= 6.0.0)
activemodel (>= 6.0.0) activemodel (>= 6.0.0)
@@ -368,19 +383,19 @@ PLATFORMS
x86_64-linux-musl x86_64-linux-musl
DEPENDENCIES DEPENDENCIES
activerecord-sqlserver-adapter
bootsnap bootsnap
brakeman brakeman
bundler-audit bundler-audit
capybara capybara
debug devise
image_processing (~> 1.2)
importmap-rails importmap-rails
jbuilder jbuilder
pg (~> 1.5) pry-rails
puma (~> 6.5) puma (~> 6.5)
pundit
rack-mini-profiler rack-mini-profiler
rails (~> 7.2) rails (~> 7.2)
redis (~> 5.3)
rspec-rails rspec-rails
rubocop-rails rubocop-rails
rubocop-rails-omakase rubocop-rails-omakase
@@ -388,6 +403,8 @@ DEPENDENCIES
selenium-webdriver selenium-webdriver
sprockets-rails sprockets-rails
stimulus-rails stimulus-rails
tailwindcss-rails
tiny_tds
turbo-rails turbo-rails
tzinfo-data tzinfo-data
web-console web-console
+2 -2
View File
@@ -1,2 +1,2 @@
web: bin/rails server -p 3000 web: bin/rails server -b 0.0.0.0 -p 3002
css: bin/rails dartsass:watch css: bin/rails tailwindcss:watch[verbose]
View File
+1
View File
@@ -2,3 +2,4 @@
//= link_directory ../stylesheets .css //= link_directory ../stylesheets .css
//= link_tree ../../javascript .js //= link_tree ../../javascript .js
//= link_tree ../../../vendor/javascript .js //= link_tree ../../../vendor/javascript .js
//= link_tree ../builds
+18
View File
@@ -0,0 +1,18 @@
@import "tailwindcss";
@theme {
/* dark blue */
--color-deepcove: #04153E;
/* medium dark blue */
--color-bluetang: #2A4B6F;
/* bright blue */
--color-atmosphere: #0096E0;
/* light blue */
--color-bluemana: #6AC8F1;
/* platinum */
--color-platinum: #E0E0E0;
/* copper */
--color-copper: #B06E30;
/* bronze */
--color-bronze: #D38F4A;
}
@@ -0,0 +1,191 @@
class EmployerSetupController < ApplicationController
def new
@top_form = EmployerSetupForm.new(session[:employer_setup_data])
case @top_form.current_step
when 'general_information'
@form = EmployerSetupGeneralInformationForm.new(session[:employer_setup_data]&.dig('general_information_data'))
when 'plans'
@form = EmployerSetupPlansForm.new(session[:employer_setup_data]&.dig('plans_data'))
when 'network_exceptions'
@form = EmployerSetupNetworkExceptionsForm.new(session[:employer_setup_data]&.dig('network_exceptions_data'))
when 'summary'
@form = @top_form
end
render @top_form.current_step_view
end
def create
@top_form = EmployerSetupForm.new(session[:employer_setup_data])
if @top_form.current_step != 'summary'
if process_step(@top_form.current_step)
session[:employer_setup_data]['current_step'] = @top_form.next_step
redirect_to new_employer_setup_path
else
render @top_form.current_step_view
end
else
if @top_form.save
session.delete(:employer_setup_data)
redirect_to root_path, notice: "Employer setup successfully!"
else
render @top_form.current_step_view
end
end
case @top_form.current_step
when 'general_information'
@form = EmployerSetupGeneralInformationForm.new(general_information_params)
if @form.valid?
session[:employer_setup_data]['general_information_data'] = general_information_params
session[:employer_setup_data]['current_step'] = @top_form.next_step
redirect_to new_employer_setup_path
else
render @top_form.current_step_view
end
when 'plans'
@form = EmployerSetupPlansForm.new(plans_params)
if @form.valid?
session[:employer_setup_data]['plans_data'] = plans_params
session[:employer_setup_data]['current_step'] = @top_form.next_step
redirect_to new_employer_setup_path
else
render @top_form.current_step_view
end
when 'network_exceptions'
@form = EmployerSetupNetworkExceptionsForm.new(network_exceptions_params)
if @form.valid?
session[:employer_setup_data]['network_exceptions_data'] = network_exceptions_params
session[:employer_setup_data]['current_step'] = @top_form.next_step
redirect_to new_employer_setup_path
else
render @top_form.current_step_view
end
when 'summary'
@form = EmployerSetupForm.new(session[:employer_setup_data])
if @form.save
session.delete(:employer_setup_data)
redirect_to root_path, notice: "Employer setup successfully!"
else
render @top_form.current_step_view
end
end
end
def update
@form = RegistrationForm.new(registration_params)
if params[:back_button]
@form.current_step = @form.previous_step
elsif params[:skip_newsletter]
@form.current_step = @form.next_step # Skip newsletter step
end
render :new
end
private
def general_information_params
params.require(:employer_setup_general_information_form).permit(
:name,
:employer_logo,
:group_number,
:dental,
:pl_plan_key,
:effect_date,
:number_of_plans,
:network,
:number_of_additional_network_logos
)
end
def plans_params
params.require(:employer_setup_plans_form).permit(
plans: permited_plans_keys,
benefit_descs: benefit_sequence_keys
)
end
def network_exceptions_params
params.require(:employer_setup_network_exceptions_form).permit(
network_exceptions: [:network_logo, exceptions: [:type, :value]],
)
end
def process_step(step_name)
form_name = "employer_setup_#{step_name}_form".camelize.constantize
form_params_name = "#{step_name}_params".to_sym
allowed_params = [:general_information_params, :plans_params, :network_exceptions_params]
if allowed_params.include?(form_params_name)
form_params = send(form_params_name)
@form = form_name.new(form_params)
if @form.valid?
session[:employer_setup_data]["#{step_name}_data"] = form_params
true
else
false
end
end
false
end
session[:employer_setup_data]['current_step'] = @top_form.next_step
redirect_to new_employer_setup_path
else
render @top_form.current_step_view
end
end
when 'general_information'
@form = EmployerSetupGeneralInformationForm.new(general_information_params)
if @form.valid?
session[:employer_setup_data]['general_information_data'] = general_information_params
session[:employer_setup_data]['current_step'] = @top_form.next_step
redirect_to new_employer_setup_path
else
render @top_form.current_step_view
end
# def employer_setup_params
# params.require(:employer_setup_form).permit(
# :current_step,
# :name,
# :employer_logo,
# :group_number,
# :pl_plan_key,
# :effect_date,
# :number_of_plans,
# :network,
# :number_of_additional_network_logos,
# network_exceptions: [:network_logo, exceptions: [:type, :value]],
# plans: permited_plans_keys,
# benefit_descs: benefit_sequence_keys
# )
# end
def benefit_sequence_keys
(1..14).map { |i| i.to_s.to_sym }
end
def permited_plans_keys
benefit_sequence_keys.push(:plan_id)
end
# def plans_params
# plans_keys = params[:plans]&.keys || []
# plans_keys.each_with_object({}) do |key, hash|
# if key == 'benefit_descs' || key.match?(/^plan_\d$/)
# hash[key.to_sym] = permited_plan_param_list
# end
# end
# end
# def permited_plan_param_list
# (1..14).map { |i| i.to_s.to_sym }.push(:plan_id)
# end
end
@@ -0,0 +1,109 @@
class EmployerSetupController < ApplicationController
def new
@employer_data = session[:employer_data] || {}
# @id_card_templates = IdCardTemplate.where.not(title: "BLANK")
# @id_card_template_benefits = IdCardTemplate.find_by(title: "BLANK").id_card_template_benefits.sort_by(&:sequence)
end
def create_employer
@employer_data = {employer: {}}
@employer_data[:employer].merge!(params.require(:employer).permit(
:name,
:group_number,
:pl_plan_key,
:effect_date
))
@employer_data[:employer].merge!(params.permit(:number_of_plans))
session[:employer_data] = @employer_data
puts session[:employer_data]
redirect_to action: :plans
end
def plans
@employer_data = session[:employer_data] || {}
@id_card_templates = IdCardBenefitsTemplate.where.not(title: "BLANK")
@id_card_template_benefits = IdCardBenefitsTemplate.find_by(title: "BLANK").id_card_benefits.sort_by(&:sequence)
end
def create_plans
@employer_data = session[:employer_data] || {}
@employer_data.merge!(params.require(:plans).permit(plans_params))
session[:employer_data] = @employer_data
redirect_to action: :networks
end
def networks
@employer_data = session[:employer_data] || {}
end
def create_provider_networks
@employer_data = session[:employer_data] || {}
@employer_data.merge!(params.require(:plans).permit(plans_params))
session[:employer_data] = @employer_data
redirect_to action: :networks
end
def process_bad_name
@final_data = session[:employer_data]
# Vhcs::HlPlanCode.create(
# group_number: @final_data['employer']['name'],
# medical_number: @final_data['employer']['group_number'],
# dental_number: ' ',
# plan_key: @final_data['employer']['pl_plan_key'],
# effect_date: @final_data['employer']['effect_date']
# )
# default = Vhcs::HLRXCrosRef.find_by(pl_plan_key: 52)
# Vhcs::HLRXCrosRef.create(
# group_no: @final_data['employer']['group_number'],
# rx_group_id: @final_data['employer']['group_number'],
# help_desk: default.help_desk,
# customer_service: default.customer_service,
# web_url: default.web_url,
# pl_plan_key: @final_data['employer']['pl_plan_key']
# )
# plans_data = @final_data['plans']
# benefit_descs = plans_data.delete('benefit_descs')
# plans_data.each do |key, value|
# plan_id = value.delete('plan_id')
# value.each do |key2, value2|
# Vhcs::HLEgglestonCardBenefit.create(
# plan_id: plan_id,
# benefit_desc: benefit_descs[key2],
# benefit: value2,
# sequence: key2,
# plan_key: @final_data['employer']['pl_plan_key']
# )
# end
# end
# Create or update your model with @final_data
# Clear the session data after successful save
session[:employer_data] = nil
# Redirect to a success page
end
private
def plans_params
plans_keys = params[:plans]&.keys || []
plans_keys.each_with_object({}) do |key, hash|
if key == 'benefit_descs' || key.match?(/^plan_\d$/)
hash[key.to_sym] = permited_plan_param_list
end
end
end
def permited_plan_param_list
(1..14).map { |i| i.to_s.to_sym }.push(:plan_id)
end
end
@@ -0,0 +1,89 @@
class EmployerSetupController < ApplicationController
def new
# session.delete(:employer_setup_data)
@form = EmployerSetupForm.new(session[:employer_setup_data])
if @form.current_step == "plans"
@id_card_templates = IdCardBenefitsTemplate.where.not(title: "BLANK")
@id_card_template_benefits = IdCardBenefitsTemplate.find_by(title: "BLANK").id_card_benefits.sort_by(&:sequence)
end
puts session[:employer_setup_data]
render "employer_setup/#{@form.current_step}" # Renders the view for the current step
end
def create
filtered_params = employer_setup_params.except(:validation_context)
@form = EmployerSetupForm.new(filtered_params)
if @form.current_step == "general" && @form.valid?(:general_info)
# @form.current_step = "plans"
@form.current_step = "networks" # TESTING, Change Back
session[:employer_setup_data] = @form.attributes.slice("current_step", "name", "employer_logo", "group_number", "pl_plan_key", "effect_date", "number_of_plans", "network", "number_of_additional_network_logos")
redirect_to new_employer_setup_path # Redirect to the next step
elsif @form.current_step == "plans" && @form.valid?(:plan_info)
if @form.number_of_additional_network_logos == 0
next_step = "summary"
else
next_step = "networks"
end
@form.current_step = next_step
session[:employer_setup_data].merge!(@form.attributes.slice("current_step", "plans", "benefit_descs"))
redirect_to new_employer_setup_path
# @form = UserOnboardingForm.new(session[:employer_setup_data]) # Re-initialize with all data
elsif @form.current_step == "networks" && @form.valid?(:network_info)
@form.current_step = "summary"
session[:employer_setup_data].merge!(@form.attributes.slice("current_step", "network_exceptions"))
redirect_to new_employer_setup_path
elsif @form.current_step == "summary"
puts @form.attributes
if @form.save
session.delete(:employer_setup_data) # Clear session data after successful save
redirect_to root_path, notice: "Employer setup successfully!"
else
render "employer_setup/summary" # Render step two again with errors
end
else
render "employer_setup/#{@form.current_step}" # Render the current step again with errors
end
end
private
def employer_setup_params
params.require(:employer_setup_form).permit(
:current_step,
:name,
:employer_logo,
:group_number,
:pl_plan_key,
:effect_date,
:number_of_plans,
:network,
:number_of_additional_network_logos,
network_exceptions: [:network_logo, exceptions: [:type, :value]],
plans: permited_plans_keys,
benefit_descs: benefit_sequence_keys
)
end
def benefit_sequence_keys
(1..14).map { |i| i.to_s.to_sym }
end
def permited_plans_keys
benefit_sequence_keys.push(:plan_id)
end
def plans_params
plans_keys = params[:plans]&.keys || []
plans_keys.each_with_object({}) do |key, hash|
if key == 'benefit_descs' || key.match?(/^plan_\d$/)
hash[key.to_sym] = permited_plan_param_list
end
end
end
def permited_plan_param_list
(1..14).map { |i| i.to_s.to_sym }.push(:plan_id)
end
end
@@ -0,0 +1,89 @@
class IdCardBenefitsTemplatesController < ApplicationController
skip_before_action :verify_authenticity_token
def new_id_card_template
@id_card_templates = IdCardTemplate.where.not(title: "BLANK")
@id_card_template_benefits = IdCardTemplate.find_by(title: "BLANK").id_card_template_benefits.sort_by(&:sequence)
end
def create_id_card_template
@id_card_template = IdCardTemplate.create(title: params[:title])
params[:benefits].each do |key, value|
IdCardTemplateBenefit.create(
sequence: key,
benefit_desc: value["desc"],
benefit: value["value"],
id_card_template: @id_card_template
)
end
respond_to do |format|
if @id_card_template.save && @id_card_template.id_card_template_benefits.length == 14
format.html { redirect_to '/dev_tools/new_id_card_setup', notice: "Template was successfully created." }
# format.json { render :show, status: :created, location: @employer }
else
format.html { render :new_id_card_template, status: :unprocessable_entity }
# format.json { render json: @employer.errors, status: :unprocessable_entity }
end
end
end
def new_id_card_setup
@id_card_templates = IdCardTemplate.where.not(title: "BLANK")
@id_card_template_benefits = IdCardTemplate.find_by(title: "BLANK").id_card_template_benefits
end
def get_templates_benefits
@id_card_benefits = IdCardBenefitsTemplate.find(params[:id]).id_card_benefits
render json: @id_card_benefits.as_json
end
def create_id_card_setup
employer_general = params['general']
hl_plan_code = Vhcs::HlPlanCode.new(
group_number: employer_general['group_number'],
medical_number: employer_general['group_number'],
dental_number: '',
plan_key: employer_general['pl_plan_key'],
effect_date: employer_general['effect_date']
)
# Replace fairos_info with template like for benefits
fairos_info = Vhcs::HLRXCrosRef.where(pl_plan_key: 52).first
hlrx_cros_ref = Vhcs::HLRXCrosRef.new(
group_no: employer_general['group_number'],
rx_group_id: employer_general['group_number'],
help_desk: fairos_info.help_desk,
customer_service: fairos_info.customer_service,
web_url: fairos_info.web_url,
pl_plan_key: employer_general['pl_plan_key']
)
number_of_plans = params[:number_of_plans].to_i
number_of_plans.each do |i|
value['benefits'].each do |ben_key, ben_value|
Vhcs::HLEgglestonCardBenefit.create(
plan_id: value['plan_id'],
benefit_desc: ben_value["desc"],
benefit: ben_value["value"],
sequence: ben_key,
plan_key: employer_general['pl_plan_key']
)
end
end
respond_to do |format|
if hl_plan_code.save && hlrx_cros_ref.save
format.html { redirect_to '/dev_tools/new_id_card_setup', notice: "Card setup was successfully created." }
# format.json { render :show, status: :created, location: @employer }
else
format.html { render :new_id_card_setup, status: :unprocessable_entity }
# format.json { render json: @employer.errors, status: :unprocessable_entity }
end
end
end
end
+106
View File
@@ -0,0 +1,106 @@
class TailwindFormBuilder < ActionView::Helpers::FormBuilder
class_attribute :text_field_helpers, default: field_helpers - [:label, :check_box, :radio_button, :fields_for, :fields, :hidden_field, :file_field]
# leans on the FormBuilder class_attribute `field_helpers`
# you'll want to add a method for each of the specific helpers listed here if you want to style them
TEXT_FIELD_STYLE = "bg-gray-200 rounded py-2 px-4 text-bluetang font-semibold leading-tight focus:outline-none focus:bg-white".freeze
SELECT_FIELD_STYLE = "block bg-gray-200 text-gray-700 py-2 px-4 rounded leading-tight focus:outline-none focus:bg-white".freeze
SUBMIT_BUTTON_STYLE = "shadow bg-bronze focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded hover:bg-copper".freeze
text_field_helpers.each do |field_method|
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{field_method}(method, options = {})
if options.delete(:tailwindified)
super
else
text_like_field(#{field_method.inspect}, method, options)
end
end
RUBY_EVAL
end
def submit(value = nil, options = {})
custom_opts, opts = partition_custom_opts(options)
classes = apply_style_classes(SUBMIT_BUTTON_STYLE, custom_opts)
super(value, {class: classes}.merge(opts))
end
def select(method, choices = nil, options = {}, html_options = {}, &block)
custom_opts, opts = partition_custom_opts(options)
classes = apply_style_classes(SELECT_FIELD_STYLE, custom_opts, method)
labels = labels(method, custom_opts[:label], options)
field = super(method, choices, opts, html_options.merge({class: classes}), &block)
labels + field
end
private
def text_like_field(field_method, object_method, options = {})
custom_opts, opts = partition_custom_opts(options)
classes = apply_style_classes(TEXT_FIELD_STYLE, custom_opts, object_method)
field = send(field_method, object_method, {
class: classes,
title: errors_for(object_method)&.join(" ")
}.compact.merge(opts).merge({tailwindified: true}))
labels = labels(object_method, custom_opts[:label], options)
labels + field
end
def labels(object_method, label_options, field_options)
label = tailwind_label(object_method, label_options, field_options)
error_label = error_label(object_method, field_options)
@template.content_tag("div", label + error_label, {class: "flex flex-col items-start"})
end
def tailwind_label(object_method, label_options, field_options)
text, label_opts = if label_options.present?
[label_options[:text], label_options.except(:text)]
else
[nil, {}]
end
label_classes = label_opts[:class] || "block text-platinum font-bold md:text-right mb-1 md:mb-0 pr-4"
label_classes += " text-yellow-800 dark:text-yellow-400" if field_options[:disabled]
label(object_method, text, {
class: label_classes
}.merge(label_opts.except(:class)))
end
def error_label(object_method, options)
if errors_for(object_method).present?
error_message = @object.errors[object_method].collect(&:titleize).join(", ")
tailwind_label(object_method, {text: error_message, class: " font-bold text-red-500"}, options)
end
end
def border_color_classes(object_method)
if errors_for(object_method).present?
" border-2 border-red-400 focus:border-rose-200"
else
" border border-platinum focus:border-yellow-700"
end
end
def apply_style_classes(classes, custom_opts, object_method = nil)
classes + border_color_classes(object_method) + " #{custom_opts[:class]}"
end
CUSTOM_OPTS = [:label, :class].freeze
def partition_custom_opts(opts)
opts.partition { |k, v| CUSTOM_OPTS.include?(k) }.map(&:to_h)
end
def errors_for(object_method)
return unless @object.present? && object_method.present?
@object.errors[object_method]
end
end
+57
View File
@@ -0,0 +1,57 @@
class EmployerSetupForm
include ActiveModel::Model
include ActiveModel::Attributes
FIRST_STEP = "general_information"
attribute :current_step, :string, default: FIRST_STEP
attribute :general_information_data
attribute :plans_data
attribute :network_exceptions_data
def initialize(params = {})
unless self.steps.first == FIRST_STEP
raise StepMisalignmentError, "FIRST_STEP does not match first entry in steps"
end
@general_information_data = EmployerSetupGeneralInformationForm.new(attributes[:general_information_data])
@plans_data = EmployerSetupPlansForm.new(attributes[:plans_data])
@network_exceptions_data = EmployerSetupNetworkExceptionsForm.new(attributes[:network_exceptions_data])
end
def steps
%w[general_information plans network_exceptions summary]
end
def current_step_view
"employer_setup/#{self.current_step}"
end
def next_step
index = steps.index(current_step)
if index && index < steps.length - 1
if steps[index + 1] == 'network_exceptions' && general_information_data.number_of_additional_network_logos == 0
steps[index + 2]
else
steps[index + 1]
end
end
end
def previous_step
index = steps.index(current_step)
steps[index - 1] if index && index > 0
end
def save
if valid?
pl_plan_key = attributes[:general_information_data][:pl_plan_key]
EmployerSetupGeneralInformationForm.new(attributes[:general_information_data]).save
EmployerSetupPlansForm.new(attributes[:plans_data]).save(pl_plan_key)
EmployerSetupNetworkExceptionsForm.new(attributes[:network_exceptions_data]).save(pl_plan_key)
true
else
false
end
end
end
@@ -0,0 +1,62 @@
class EmployerSetupForm
include ActiveModel::Model
include ActiveModel::Attributes
attribute :current_step, :string, default: "general"
attribute :name, :string
attribute :employer_logo
attribute :group_number, :string
attribute :pl_plan_key, :string
attribute :effect_date, :string
attribute :number_of_plans, :integer
attribute :network, :string
attribute :number_of_additional_network_logos, :integer
attribute :plans, array: true, default: -> { [] }
# attribute :benefit_descs, :hash, default: -> { {} }
attribute :network_exceptions, array: true, default: -> { [] }
attr_accessor :benefit_descs
# Define validations based on the current step
with_options on: :general_info do
validates :name, presence: true
validates :employer_logo, presence: true
validates :group_number, presence: true
validates :pl_plan_key, presence: true
validates :effect_date, presence: true
validates :number_of_plans, presence: true
validates :network, presence: true
# validates :number_of_additional_network_logos, presence: true if network = "cigna+"
end
with_options on: :plan_info do
validates :plans, presence: true
# validates :benefit_descs, presence: true
end
with_options on: :network_info do
# validates :network_exceptions, presence: true if number_of_additional_network_logos > 0
end
# def initialize(params = {})
# super(params)
# # Ensure the attribute is a hash after initialization
# @benefit_descs = params[:benefit_descs].to_h if params[:benefit_descs]
# end
def benefit_descs
@benefit_descs ||= {}
end
def save
# Implement logic to save data to models after all steps are complete
# For example, create a User record with the collected data
if valid? && step == total_steps
# User.create!(name: name, email: email, password: password)
true
else
false
end
end
end
@@ -0,0 +1,72 @@
class EmployerSetupGeneralInformationForm
include ActiveModel::Model
include ActiveModel::Attributes
attribute :name, :string
attribute :employer_logo
attribute :group_number, :string
attribute :dental, :boolean
attribute :pl_plan_key, :string
attribute :effect_date, :string
attribute :number_of_plans, :integer
attribute :network, :string
attribute :number_of_additional_network_logos, :integer
validates :name, presence: true
validates :employer_logo, presence: true
validates :group_number, presence: true
validates :pl_plan_key, presence: true
validates :effect_date, presence: true
validates :number_of_plans, presence: true
validates :network, presence: true
# validates :number_of_additional_network_logos, presence: true if network = "cigna+"
# def initialize(params = {})
# super(params)
# # Ensure the attribute is a hash after initialization
# @benefit_descs = params[:benefit_descs].to_h if params[:benefit_descs]
# end
def save
# Implement logic to save data to models after all steps are complete
# For example, create a User record with the collected data
if valid?
hl_plan_code = Vhcs::HlPlanCode.create!(
group_number: group_number,
medical_number: group_number,
dental_number: '',
plan_key: pl_plan_key,
effect_date: effect_date
)
# Replace fairos_info with template like for benefits
fairos_info = Vhcs::HLRXCrosRef.where(pl_plan_key: 52).first
hlrx_cros_ref = Vhcs::HLRXCrosRef.create!(
group_no: group_number,
rx_group_id: group_number,
help_desk: fairos_info.help_desk,
customer_service: fairos_info.customer_service,
web_url: fairos_info.web_url,
pl_plan_key: pl_plan_key
)
web_employer = BrittonWeb::Employers.create!(
pl_plan_key: pl_plan_key,
dental_plan: dental,
single_card_template: 'FairosRxIDCard',
logo: employer_logo.filename
)
BrittonWeb::NetworkLogos.create!(
employer: web_employer,
net_logo: network,
default: true
)
true
else
false
end
end
end
@@ -0,0 +1,46 @@
class EmployerSetupNetworkExceptionsForm
include ActiveModel::Model
include ActiveModel::Attributes
Network_exception = Struct.new(:network_logo, :exceptions)
attribute :network_exceptions, :array_of_items, default: -> { [] }
# validates :network_exceptions, presence: true if number_of_additional_network_logos > 0
# def initialize(params = {})
# super(params)
# # Ensure the attribute is a hash after initialization
# @benefit_descs = params[:benefit_descs].to_h if params[:benefit_descs]
# end
def save(pl_plan_key)
# Implement logic to save data to models after all steps are complete
# For example, create a User record with the collected data
if valid?
employer = BrittonWeb::Employers.find_by(pl_plan_key: pl_plan_key)
network_exceptions.each do |ne|
BrittonWeb::NetworkLogos.create!(
employer: employer,
net_logo: ne.network_logo,
exception_type: ne.type,
exception_value: ne.value,
default: false
)
end
true
else
false
end
end
end
class NetworkException
include ActiveModel::Model
include ActiveModel::Attributes
attribute :network_logo
attribute :exceptions, array: true, default: -> { [] }
end
+49
View File
@@ -0,0 +1,49 @@
class EmployerSetupPlansForm
include ActiveModel::Model
include ActiveModel::Attributes
attribute :plans, array: true, default: -> { [] }
# attribute :benefit_descs, :hash, default: -> { {} }
attr_accessor :id_card_templates
attr_accessor :id_card_template_benefits
attr_accessor :benefit_descs
validates :plans, presence: true
# validates :benefit_descs, presence: true
def initialize(params = {})
super(params)
@id_card_templates = IdCardBenefitsTemplate.where.not(title: "BLANK")
@id_card_template_benefits = IdCardBenefitsTemplate.find_by(title: "BLANK").id_card_benefits.sort_by(&:sequence)
end
# def benefit_descs
# @benefit_descs ||= {}
# end
def save(pl_plan_key)
# Implement logic to save data to models after all steps are complete
# For example, create a User record with the collected data
if valid?
plans.each do |plan|
plan_id = plan.delete(:plan_id)
plan.each do |key, value|
Vhcs::HLEgglestonCardBenefit.create(
plan_id: plan_id,
benefit_desc: benefit_descs["#{key}"],
benefit: value,
sequence: key,
plan_key: pl_plan_key
)
end
end
true
else
false
end
end
end
+2
View File
@@ -0,0 +1,2 @@
module IdCardEmployersHelper
end
-2
View File
@@ -3,5 +3,3 @@ import "@hotwired/turbo-rails"
import "controllers" import "controllers"
import "trix" import "trix"
import "@rails/actiontext" import "@rails/actiontext"
console.log('Hello World from application.js');
@@ -7,5 +7,3 @@ application.debug = false
window.Stimulus = application window.Stimulus = application
export { application } export { application }
console.log('Hello World from controllers/application.js');
@@ -0,0 +1,38 @@
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static values = { url: String };
static targets = ["benefit_1", "benefit_2", "benefit_3", "benefit_4", "benefit_5", "benefit_6", "benefit_7", "benefit_8", "benefit_9", "benefit_10", "benefit_11", "benefit_12", "benefit_13", "benefit_14"];
async fetchData(event) {
const templateId = event.target.value;
if (!templateId) {
this.clearFields();
return;
}
const url = "/id_card_benefits_templates/get_templates_benefits/:id".replace(':id', templateId);
const response = await fetch(url);
const templateBenefitsData = await response.json();
this.nameTarget.value = templateData.name;
this.descriptionTarget.value = templateData.description;
}
clearFields() {
this.nameTarget.value = '';
this.descriptionTarget.value = '';
}
updateFields(templateBenefitsData) {
templateBenefitsData.forEach(function(benefit) {
const propertyName = `benefit_${benefit.sequence}`
this[propertyName].value = benefit.benefit
});
}
}
// this[propertyName]
// const propertyName = `${valueName}Value`;
@@ -0,0 +1,37 @@
import { Controller } from "@hotwired/stimulus";
export default class extends Controller {
static targets = ["numberInput", "planFieldsContainer", "template"];
connect() {
this.updatePlanFields();
}
updatePlanFields() {
const desiredCount = parseInt(this.numberInputTarget.value || 1, 10);
const currentCount = this.planFieldsContainerTarget.children.length;
if (desiredCount > currentCount) {
this.addPlanFields(desiredCount - currentCount);
} else if (desiredCount < currentCount) {
this.removePlanFields(currentCount - desiredCount);
}
}
addPlanFields(count) {
for (let i = 0; i < count; i++) {
const newPlanField = this.templateTarget.content.cloneNode(true);
// Replace '__INDEX__' with a unique value for nested attributes
// e.g., using Date.now() or a counter
const uniqueIndex = Date.now() + i;
newPlanField.innerHTML = newPlanField.innerHTML.replace(/__INDEX__/g, uniqueIndex);
this.planFieldsContainerTarget.appendChild(newPlanField);
}
}
removePlanFields(count) {
for (let i = 0; i < count; i++) {
this.planFieldsContainerTarget.lastElementChild.remove();
}
}
}
@@ -0,0 +1,22 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["divA"] // Add targets for all your divs
connect() {
this.toggleDivs() // Call on connect to set initial state
}
toggleDivs() {
const selectedValue = this.element.querySelector('select').value;
console.log("sv: ")
// Hide all divs first
this.divATarget.classList.add("hidden");
// Show the relevant div based on selection
if (selectedValue === "cig+") {
this.divATarget.classList.remove("hidden");
}
}
}
+2
View File
@@ -2,4 +2,6 @@
class ApplicationRecord < ActiveRecord::Base class ApplicationRecord < ActiveRecord::Base
primary_abstract_class primary_abstract_class
establish_connection :dev_tools
end end
-5
View File
@@ -1,5 +0,0 @@
class Article < ApplicationRecord
has_many :comments, dependent: :destroy
has_rich_text :content
validates_presence_of :title
end
-4
View File
@@ -1,4 +0,0 @@
class Comment < ApplicationRecord
belongs_to :article
broadcasts_to :article
end
+3
View File
@@ -0,0 +1,3 @@
class IdCardBenefit < ApplicationRecord
belongs_to :id_card_benefits_template
end
+5
View File
@@ -0,0 +1,5 @@
class IdCardBenefitsTemplate < ApplicationRecord
has_many :id_card_benefits
end
@@ -0,0 +1,15 @@
module Vhcs
class HlEgglestonCardBenefit < VhcsRecord
self.table_name = 'HLEgglestonCardBenefit'
alias_attribute :id, :Id
alias_attribute :plan_id, :PlanId
alias_attribute :benefit_desc, :BenefitDesc
alias_attribute :benefit, :Benefit
alias_attribute :sequence, :Sequence
alias_attribute :plan_key, :PlanKey
end
end
+14
View File
@@ -0,0 +1,14 @@
module VHCS
class HlPlanCode < VhcsRecord
self.table_name = 'HlPlanCode'
alias_attribute :id, :ID
alias_attribute :group_number, :GroupNumber
alias_attribute :medical_number, :MedicalNumber
alias_attribute :dental_number, :DentalNumber
alias_attribute :plan_key, :PlanKey
alias_attribute :effect_date, :EffectDate
end
end
+15
View File
@@ -0,0 +1,15 @@
module Vhcs
class HLRXCrosRef < VhcsRecord
self.table_name = 'HLRXCrosRef'
alias_attribute :group_no, :GroupNo
alias_attribute :rx_group_id, :RXGroupID
alias_attribute :help_desk, :HelpDesk
alias_attribute :customer_service, :CustomerService
alias_attribute :web_url, :WebUrl
alias_attribute :pl_plan_key, :PLPlanKey
end
end
+5
View File
@@ -0,0 +1,5 @@
class VhcsRecord < ActiveRecord::Base
self.abstract_class = true
# establish_connection :vhcs
connects_to database: { writing: :vhcs, reading: :vhcs }
end
+23
View File
@@ -0,0 +1,23 @@
class ArrayOfItemsType < ActiveModel::Type::Value
# The `cast` method is used to convert an incoming value into the desired type.
def cast(value)
return unless value.present?
Array.wrap(value).map do |item_data|
# Assuming item_data is a hash, this creates an instance of the Item class.
# You can modify this part to match your object's initializer.
if item_data.is_a?(Hash)
Item.new(item_data)
else
item_data # Return the item as-is if it's already an object
end
end
end
# This method is used when defining the type to convert it to a string for serialization.
def serialize(value)
value
end
end
ActiveModel::Type.register(:array_of_items, ArrayOfItemsType)
+56
View File
@@ -0,0 +1,56 @@
<div class="bg-deepcove min-h-screen w-full flex flex-col">
<h1 class="font-bold text-4xl text-platinum">New Employer Setup</h1>
<h3 class="font-bold text-2xl text-bluemana">General Information</h3>
<%= form_with model: @form, url: employer_setup_index_path, local: true do |f| %>
<div class="flex flex-col my-8 space-y-6">
<div class="flex space-x-10">
<div class="w-1/5">
<%= f.text_field :name, label: { text: "Employer Name" }, class: "w-full" %>
</div>
<div class="w-1/5">
<%= f.text_field :group_number, label: { text: "Group/Medical Number" }, class: "w-full" %>
</div>
<div>
<%= f.check_box :dental %>
</div>
</div>
<div class="flex space-x-10">
<div class="w-1/5">
<%= f.text_field :pl_plan_key, label: { text: "Pl Plan Key" }, class: "w-full" %>
</div>
<div class="w-1/5">
<%= f.text_field :effect_date, label: { text: "Effective Date" }, class: "w-full" %>
</div>
</div>
<div class="flex space-x-10">
<div class="w-1/5">
<%= f.select :number_of_plans, options_for_select((1..6).to_a), label: { text: "Number of Plans" }, class: "w-1/3" %>
</div>
<div class="w-1/5">
<%= f.select :network, options_for_select([["Cigna", "cig"], ["Cigna+Regional", "cig+"], ["Medcost", "med"]]), label: { text: "Provider Network" }, data: { controller: "form-toggle", action: "change->form-toggle#toggleDivs" }, class: "w-full" %>
</div>
<div id="div-a" class="w-1/5" data-form-toggle-target="divA">
<%= f.select :number_of_additional_network_logos, options_for_select((0..6).to_a), label: { text: "Number of Additional Network Logos" }, class: "w-1/3" %>
</div>
</div>
<div class="flex space-x-5 items-center mt-4">
<label for="file_upload_input" class="cursor-pointer bg-atmosphere hover:bg-bluetang text-platinum font-bold py-2 px-4 rounded border border-platinum">
Choose Employer Logo File
</label>
<span id="file_name_display" class="ml-2 text-bluemana font-semibold">No file chosen</span>
<%= f.file_field :employer_logo, class: "hidden", id: "file_upload_input" %>
</div>
<div class="pt-8">
<%= f.submit "Continue to Plans" %>
</div>
</div>
<% end %>
</div>
<script>
document.getElementById('file_upload_input').addEventListener('change', function(e) {
var fileName = e.target.files[0] ? e.target.files[0].name : 'No file chosen';
document.getElementById('file_name_display').textContent = fileName;
});
</script>
@@ -0,0 +1,41 @@
<div class="bg-deepcove min-h-screen w-full flex flex-col">
<h1 class="font-bold text-4xl text-platinum">New Employer Setup</h1>
<h3 class="font-bold text-2xl text-bluemana">Provider Network</h3>
<%= form_with model: @form, url: employer_setup_index_path, local: true do |f| %>
<% @form.number_of_additional_network_logos.to_i.times do |i| %>
<%= f.fields_for :network_exceptions do |network_fields| %>
<div class="w-full flex flex-col my-8 space-y-6">
<div class="flex space-x-5 items-center mt-4">
<label for="file_upload_input" class="cursor-pointer bg-atmosphere hover:bg-bluetang text-platinum font-bold py-2 px-4 rounded border border-platinum">
Choose Network Logo File
</label>
<span id="file_name_display" class="ml-2 text-bluemana font-semibold">No file chosen</span>
<%= network_fields.file_field :network_logo, class: "hidden", id: "file_upload_input" %>
</div>
<% 2.to_i.times do |j| %>
<%= network_fields.fields_for :exceptions do |exception_fields| %>
<div class="flex space-x-10">
<div class="w-1/5">
<%= exception_fields.select :type, options_for_select(["Zipcode","State"]), label: { text: "Exception Type" }, prompt: "Select Type", class: "w-full" %>
</div>
<div class="w-1/5">
<%= exception_fields.text_field :value, label: { text: "Exception Value" }, class: "w-full" %>
</div>
</div>
<% end %>
<% end %>
</div>
<% end %>
<% end %>
<div class="py-10">
<%= f.submit "Continue to Summary" %>
</div>
<% end %>
</div>
<script>
document.getElementById('file_upload_input').addEventListener('change', function(e) {
var fileName = e.target.files[0] ? e.target.files[0].name : 'No file chosen';
document.getElementById('file_name_display').textContent = fileName;
});
</script>
@@ -0,0 +1,38 @@
<div class="bg-deepcove min-h-screen w-full flex flex-col">
<h1 class="font-bold text-4xl text-platinum">New Employer Setup</h1>
<%= form_with url: 'create_plans', method: :post do |form| %>
<div class="w-full flex">
<div class="flex flex-col mr-4">
<% @id_card_template_benefits.each do |bene| %>
<div>
<%= form.text_field "plans[benefit_descs][#{bene.sequence}]", label: { text: "Benefit Description" }, value: "#{bene.benefit_desc}" %>
</div>
<% end %>
</div>
<% @employer_data['employer']['number_of_plans'].to_i.times do |i| %>
<div class="flex flex-col">
<div>
<%= form.text_field "plans[plan_#{i}][plan_id]", label: { text: "Plan Id" } %>
</div>
<div class="bg-gray-200 rounded py-2 px-4 text-bluetang font-semibold leading-tight">
<select data-action="benefits-template-picker#fetchData" data-benefits-template-picker-url-value="/id_card_benefits_templates/get_templates_benefits/:id">
<option value="">Select Existing Template (optional)</option>
<% @id_card_templates.each do |temp| %>
<option value="<%= temp.id %>"><%= temp.name %></option>
<% end %>
</select>
</div>
<% @id_card_template_benefits.each do |bene| %>
<div>
<div>
<%= form.text_field "plans[plan_#{i}][#{bene.sequence}]", label: { text: "Benefit Value" }, data: { benefits_template_picker_target: "benefit_#{bene.sequence}" } %>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
<%= form.submit "Summary" %>
</div>
<% end %>
</div>
+47
View File
@@ -0,0 +1,47 @@
<div class="bg-deepcove min-h-screen w-full flex flex-col">
<h1 class="font-bold text-4xl text-platinum">New Employer Setup</h1>
<h3 class="font-bold text-2xl text-bluemana">Medical Plans</h3>
<div class="flex flex-col pl-6">
<%= form_with model: @form, url: employer_setup_index_path, local: true do |f| %>
<div class="w-full flex my-8">
<div class="flex flex-col justify-end pr-6">
<% @id_card_template_benefits.each do |bene| %>
<%= f.fields_for :benefit_descs do |bd_fields| %>
<div>
<%= bd_fields.text_field "#{bene.sequence}", label: { text: "Benefit Description #{bene.sequence}" }, value: "#{bene.benefit_desc}" %>
</div>
<% end %>
<% end %>
</div>
<% @form.number_of_plans.to_i.times do |i| %>
<% border_colors = ['border-atmosphere', 'border-copper', 'border-bluemana'] %>
<% text_colors = ['text-atmosphere', 'text-copper', 'text-bluemana'] %>
<div class="inline-flex flex-col justify-end pr-6 pl-1 relative">
<div class="absolute left-0 top-[2%] h-[98%] border-l-4 <%= border_colors[i] %> rounded-bl-lg"></div>
<div class="font-bold text-2xl <%= text_colors[i] %> -ml-[6px] z-2 w-full">
<%= "Plan #{i + 1}" %>
</div>
<%= f.fields_for :plans do |plan_fields| %>
<div class="pl-1 w-full">
<%= plan_fields.text_field :plan_id, label: { text: "Plan Id" }, class: "w-full" %>
</div>
<div class="pl-1" data-controller="benefits_template_picker_controller">
<%= f.select :template_id, options_from_collection_for_select(@id_card_templates, :id, :name), { prompt: "Select Existing Template (optional)", data: { action: "benefits-template-picker#fetchData" }} %>
</div>
<% @id_card_template_benefits.each do |bene| %>
<div>
<div class="pl-1 w-full">
<%= plan_fields.text_field "#{bene.sequence}", label: { text: "Benefit Value #{bene.sequence}" }, data: { benefits_template_picker_target: "benefit_#{bene.sequence}" }, class: "w-full" %>
</div>
</div>
<% end %>
<% end %>
</div>
<% end %>
</div>
<div class="py-10">
<%= f.submit "Continue to Provider Network" %>
</div>
<% end %>
</div>
</div>
@@ -0,0 +1,9 @@
<div class="bg-deepcove min-h-screen w-full flex flex-col">
<h1 class="font-bold text-4xl text-platinum">New Employer Setup</h1>
<h3 class="font-bold text-2xl text-bluemana">Summary</h3>
<%= form_with model: @form, url: employer_setup_index_path, local: true do |f| %>
<div class="py-10">
<%= f.submit "Submit" %>
</div>
<% end %>
</div>
+4 -2
View File
@@ -5,13 +5,15 @@
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %> <%= csrf_meta_tags %>
<%= csp_meta_tag %> <%= csp_meta_tag %>
<%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %> <%= javascript_importmap_tags %>
<link rel="stylesheet" href="https://cdn.simplecss.org/simple.min.css">
</head> </head>
<body> <body class="w-full flex bg-deepcove">
<main class="w-11/12 mt-28 px-5 flex">
<%= yield %> <%= yield %>
</main>
</body> </body>
</html> </html>
Executable → Regular
View File
Executable → Regular
View File
+11
View File
@@ -0,0 +1,11 @@
#!/bin/bash
set -e
# Wait for SQL Server to be ready
# You can adjust the sleep time if needed
sleep 7
# Run init-script with long timeout - and make it run in the background
/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "Br1tt0nPassw0rd" -i init.sql &
# Start SQL Server
/opt/mssql/bin/sqlservr
+16
View File
@@ -0,0 +1,16 @@
#!/usr/bin/env sh
if ! gem list foreman -i --silent; then
echo "Installing foreman..."
gem install foreman
fi
# Default to port 3000 if not specified
export PORT="${PORT:-3000}"
# Let the debug gem allow remote connections,
# but avoid loading until `debugger` is called
export RUBY_DEBUG_OPEN="true"
export RUBY_DEBUG_LAZY="true"
exec foreman start -f Procfile.dev "$@"
Executable → Regular
View File
+2
View File
@@ -4,6 +4,8 @@ set -e
# Remove a potentially pre-existing server.pid for Rails. # Remove a potentially pre-existing server.pid for Rails.
rm -f /usr/src/app/tmp/pids/server.pid rm -f /usr/src/app/tmp/pids/server.pid
rm -rf /usr/local/bundle/cache/*.gem
echo "bundle install..." echo "bundle install..."
bundle check || bundle install --jobs 4 bundle check || bundle install --jobs 4
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
Executable → Regular
View File
+18 -14
View File
@@ -2,41 +2,45 @@ services:
web: web:
build: build:
context: ./ context: ./
dockerfile: development.Dockerfile dockerfile: development3.Dockerfile
command: bash -c "rm -f tmp/pids/server.pid && bin/rails s -p 3000 -b '0.0.0.0'" command: bash -c "rm -f tmp/pids/server.pid && bin/dev"
volumes: volumes:
- .:/usr/src/app - .:/usr/src/app
- bundle:/usr/local/bundle - bundle:/usr/local/bundle
ports: ports:
- "3000:3000" - "3002:3002"
env_file: env_file:
- .env - .env
environment: environment:
- HISTFILE=/usr/src/app/log/.bash_history - HISTFILE=/usr/src/app/log/.bash_history
- RAILS_ENV=development
- TAILWIND_POLLING=true
tty: true
stdin_open: true
depends_on: depends_on:
db: db:
condition: service_healthy condition: service_healthy
redis: redis:
condition: service_started condition: service_started
db: db:
image: postgres:17 build:
ports: context: .
- "5432:5432" dockerfile: Dockerfile.db
environment:
- POSTGRES_PASSWORD=changeme
volumes: volumes:
- pg_data:/var/lib/postgresql/data - ./mssql-data:/var/opt/mssql
ports:
- "1434:1434"
healthcheck: healthcheck:
test: pg_isready -U postgres test: ["CMD", "/opt/mssql-tools/bin/sqlcmd", "-Usa", "-PBr1tt0nPassw0rd", "-Q", "select 1"]
interval: 2s interval: 10s
timeout: 5s timeout: 3s
retries: 30 retries: 10
start_period: 10s
redis: redis:
image: redis image: redis
volumes: volumes:
- redis_data:/data - redis_data:/data
volumes: volumes:
pg_data:
redis_data: redis_data:
bundle: bundle:
+2
View File
@@ -28,6 +28,8 @@ module Railsondocker
# Common ones are `templates`, `generators`, or `middleware`, for example. # Common ones are `templates`, `generators`, or `middleware`, for example.
config.autoload_lib(ignore: %w[assets tasks]) config.autoload_lib(ignore: %w[assets tasks])
config.autoload_paths += %W(#{config.root}/app/form_builders)
# Configuration for the application, engines, and railties goes here. # Configuration for the application, engines, and railties goes here.
# #
# These settings can be overridden in specific environments using the files # These settings can be overridden in specific environments using the files
+23 -9
View File
@@ -13,16 +13,30 @@
# gem "pg" # gem "pg"
# #
default: &default default: &default
adapter: postgresql adapter: sqlserver
encoding: unicode mode: dblib
# For details on connection pooling, see Rails configuration guide # For details on connection pooling, see Rails configuration guide
# https://guides.rubyonrails.org/configuring.html#database-pooling # https://guides.rubyonrails.org/configuring.html#database-pooling
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development: development:
dev_tools:
<<: *default <<: *default
database: railsondocker_development host: db
database: dev_tools_dev
username: sa
password: Br1tt0nPassw0rd
vhcs:
<<: *default
# host: 10.41.82.72 #Prod
host: 10.41.82.73 #Dev
port: 1433
database: VHCS_HIPAA
username: BSTI
password: BSTIBOY
database_tasks: false
tds_version: 7.3
# The specified database role being used to connect to PostgreSQL. # The specified database role being used to connect to PostgreSQL.
# To create additional roles in PostgreSQL see `$ createuser --help`. # To create additional roles in PostgreSQL see `$ createuser --help`.
@@ -54,9 +68,9 @@ development:
# Warning: The database defined as "test" will be erased and # Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake". # re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production. # Do not set this db to the same as development or production.
test: # test:
<<: *default # <<: *default
database: railsondocker_test # database: railsondocker_test
# As with config/credentials.yml, you never want to store sensitive information, # As with config/credentials.yml, you never want to store sensitive information,
# like your database password, in your source code. If your source code is # like your database password, in your source code. If your source code is
@@ -78,6 +92,6 @@ test:
# Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # Read https://guides.rubyonrails.org/configuring.html#configuring-a-database
# for a full overview on how database connection configuration can be specified. # for a full overview on how database connection configuration can be specified.
# #
production: # production:
<<: *default # <<: *default
url: <%= ENV['DATABASE_URL'] %> # url: <%= ENV['DATABASE_URL'] %>
+1 -1
View File
@@ -44,7 +44,7 @@ Rails.application.configure do
# caching is enabled. # caching is enabled.
config.action_mailer.perform_caching = false config.action_mailer.perform_caching = false
config.action_mailer.default_url_options = { host: "localhost", port: 3000 } config.action_mailer.default_url_options = { host: "localhost", port: 3002 }
# Print deprecation notices to the Rails logger. # Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log config.active_support.deprecation = :log
+4
View File
@@ -0,0 +1,4 @@
# config/initializers/action_view.rb
Rails.application.config.to_prepare do
ActionView::Base.default_form_builder = TailwindFormBuilder
end
+3 -1
View File
@@ -24,10 +24,12 @@ threads_count = ENV.fetch("RAILS_MAX_THREADS", 3)
threads threads_count, threads_count threads threads_count, threads_count
# Specifies the `port` that Puma will listen on to receive requests; default is 3000. # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
port ENV.fetch("PORT", 3000) port ENV.fetch("PORT", 3002)
# Allow puma to be restarted by `bin/rails restart` command. # Allow puma to be restarted by `bin/rails restart` command.
plugin :tmp_restart plugin :tmp_restart
plugin :tailwindcss
# Only use a pidfile when requested # Only use a pidfile when requested
pidfile ENV["PIDFILE"] if ENV["PIDFILE"] pidfile ENV["PIDFILE"] if ENV["PIDFILE"]
+1
View File
@@ -1,6 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
Rails.application.routes.draw do Rails.application.routes.draw do
resources :employer_setup, only: [:new, :create]
get "welcome/index" get "welcome/index"
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
@@ -1,10 +0,0 @@
class CreateArticles < ActiveRecord::Migration[7.0]
def change
create_table :articles do |t|
t.string :title
t.text :content
t.timestamps
end
end
end
@@ -1,10 +0,0 @@
class CreateComments < ActiveRecord::Migration[7.0]
def change
create_table :comments do |t|
t.references :article, null: false, foreign_key: true
t.text :content
t.timestamps
end
end
end
@@ -0,0 +1,9 @@
class CreateIdCardBenefitsTemplates < ActiveRecord::Migration[7.2]
def change
create_table :id_card_benefits_templates do |t|
t.string :title
t.timestamps
end
end
end
@@ -0,0 +1,12 @@
class CreateIdCardBenefits < ActiveRecord::Migration[7.2]
def change
create_table :id_card_benefits do |t|
t.string :benefit_desc
t.string :benefit
t.integer :sequence
t.references :id_card_benefits_template, null: false, foreign_key: true
t.timestamps
end
end
end
+10 -12
View File
@@ -10,10 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.1].define(version: 2023_03_26_154219) do ActiveRecord::Schema[7.2].define(version: 2025_11_04_171752) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "action_text_rich_texts", force: :cascade do |t| create_table "action_text_rich_texts", force: :cascade do |t|
t.string "name", null: false t.string "name", null: false
t.text "body" t.text "body"
@@ -52,22 +49,23 @@ ActiveRecord::Schema[7.1].define(version: 2023_03_26_154219) do
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
end end
create_table "articles", force: :cascade do |t| create_table "id_card_benefits", force: :cascade do |t|
t.string "title" t.string "benefit_desc"
t.text "content" t.string "benefit"
t.integer "sequence"
t.bigint "id_card_benefits_template_id", null: false
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.index ["id_card_benefits_template_id"], name: "index_id_card_benefits_on_id_card_benefits_template_id"
end end
create_table "comments", force: :cascade do |t| create_table "id_card_benefits_templates", force: :cascade do |t|
t.bigint "article_id", null: false t.string "title"
t.text "content"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.index ["article_id"], name: "index_comments_on_article_id"
end end
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "comments", "articles" add_foreign_key "id_card_benefits", "id_card_benefits_templates"
end end
+9
View File
@@ -9,3 +9,12 @@
# ["Action", "Comedy", "Drama", "Horror"].each do |genre_name| # ["Action", "Comedy", "Drama", "Horror"].each do |genre_name|
# MovieGenre.find_or_create_by!(name: genre_name) # MovieGenre.find_or_create_by!(name: genre_name)
# end # end
# Pull one planid, return data, run this
# data.each do |bene|
# IdCardBenefit.create(
# benefit_desc: bene.benefit_desc,
# sequence: bene.sequence,
# id_card_benefits_template: temp
# )
# end
+59 -4
View File
@@ -13,16 +13,71 @@ RUN --mount=type=cache,target=/var/cache/apt \
apt-get update -qq \ apt-get update -qq \
&& apt-get install -yq --no-install-recommends \ && apt-get install -yq --no-install-recommends \
build-essential \ build-essential \
cmake \
ruby-dev \
gnupg2 \ gnupg2 \
less \ less \
git \ git \
libpq-dev \ unixodbc \
postgresql-client \ unixodbc-dev \
tdsodbc \
freetds-dev \
libvips \ libvips \
libpq-dev \
curl \ curl \
libjemalloc2 \ libjemalloc2 \
pkg-config \ pkg-config \
libyaml-dev python3-dev \
wget \
libtool \
libssl-dev && \
rm -rf /var/lib/apt/lists/*
ARG WATCHMAN_VERSION=v2025.11.10.00
WORKDIR /tmp
RUN git clone https://github.com/facebook/watchman.git -b ${WATCHMAN_VERSION} --depth 1 && \
cd watchman && \
./autogen.sh && \
./configure && \
make && \
make install
# Download and install Watchman from the pre-compiled binary
# RUN curl -L https://github.com/facebook/watchman/archive/refs/tags/v${WATCHMAN_VERSION}.zip -o watchman.zip \
# && unzip watchman.zip \
# && rm watchman.zip \
# && cd watchman-${WATCHMAN_VERSION} \
# && mkdir -p /usr/local/{bin,lib} /usr/local/var/run/watchman \
# && chmod 755 /usr/local/bin/watchman \
# && chmod 2777 /usr/local/var/run/watchman \
# && cd .. \
# && rm -fr ${WATCHMAN_VERSION}
# OS Level Dependencies
# RUN --mount=type=cache,target=/var/cache/apt \
# --mount=type=cache,target=/var/lib/apt,sharing=locked \
# --mount=type=tmpfs,target=/var/log \
# rm -f /etc/apt/apt.conf.d/docker-clean; \
# echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache; \
# apt-get update -qq \
# && apt-get install -yq --no-install-recommends \
# build-essential \
# ruby-dev \
# gnupg2 \
# less \
# git \
# unixodbc \
# unixodbc-dev \
# tdsodbc \
# freetds-dev \
# libvips \
# libpq-dev \
# curl \
# libjemalloc2 \
# pkg-config \
# libtool \
# libssl-dev && \
# rm -rf /var/lib/apt/lists/*
ENV LANG=C.UTF-8 \ ENV LANG=C.UTF-8 \
BUNDLE_JOBS=4 \ BUNDLE_JOBS=4 \
@@ -32,6 +87,6 @@ WORKDIR /usr/src/app
ENTRYPOINT ["./bin/docker-entrypoint-development"] ENTRYPOINT ["./bin/docker-entrypoint-development"]
EXPOSE 3000 EXPOSE 3002
CMD ["./bin/rails", "server"] CMD ["./bin/rails", "server"]
+73
View File
@@ -0,0 +1,73 @@
# ----- Build Stage -----
# Using a specific Ruby version (e.g., 3.3) for stability
ARG RUBY_VERSION=3.3.9
FROM ruby:$RUBY_VERSION as builder
# Install system dependencies needed for Ruby gems and asset building
RUN apt-get update -qq && apt-get install -y \
build-essential \
libpq-dev \
libvips \
nodejs \
npm \
git \
curl \
watchman \
&& rm -rf /var/lib/apt/lists/* \
# For TailwindCSS, install the npm package instead of relying on the system executable
# as there have been issues with architecture mismatches in containers
&& npm install -g tailwindcss
# Set the working directory inside the container
WORKDIR /usr/src/app
# Copy and install Ruby dependencies
COPY Gemfile Gemfile.lock ./
RUN bundle install
# Copy the rest of the application code
COPY . .
# Precompile assets for production using the installed Tailwind CLI
# This uses the installed 'tailwindcss' executable rather than the gem's wrapper
# RUN bundle exec rails assets:precompile
# ----- Production Stage -----
# Use a smaller Ruby image for the final production build
FROM ruby:$RUBY_VERSION-slim
# Install production system dependencies
RUN --mount=type=cache,target=/var/cache/apt \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
--mount=type=tmpfs,target=/var/log \
rm -f /etc/apt/apt.conf.d/docker-clean; \
apt-get update -qq \
&& apt-get install -yq --no-install-recommends \
build-essential \
less \
git \
tdsodbc \
freetds-dev \
libvips \
libpq-dev
ENV LANG=C.UTF-8 \
BUNDLE_JOBS=4 \
BUNDLE_RETRY=3
WORKDIR /usr/src/app
# Copy runtime Ruby dependencies and the precompiled assets from the builder stage
COPY --from=builder /usr/local/bundle /usr/local/bundle
COPY --from=builder /usr/src/app /usr/src/app
COPY --from=builder /usr/local/bin/watchman /usr/local/bin/watchman
COPY --from=builder /usr/local/bin/watchman-wait /usr/local/bin/watchman-wai
# The entrypoint script is a good practice for handling Rails server startup
ENTRYPOINT ["./bin/docker-entrypoint-development"]
# Expose the application port
EXPOSE 3002
# Set the default command to run the Rails server
CMD ["./bin/rails", "server"]
+46
View File
@@ -0,0 +1,46 @@
# ----- Build Stage -----
# Using a specific Ruby version (e.g., 3.3) for stability
ARG RUBY_VERSION=3.3.9
FROM docker.io/library/ruby:$RUBY_VERSION-slim as base
# Install production system dependencies
RUN --mount=type=cache,target=/var/cache/apt \
--mount=type=cache,target=/var/lib/apt,sharing=locked \
--mount=type=tmpfs,target=/var/log \
rm -f /etc/apt/apt.conf.d/docker-clean; \
apt-get update -qq \
&& apt-get install -yq --no-install-recommends \
build-essential \
less \
git \
tdsodbc \
freetds-dev \
libvips \
libpq-dev
ENV LANG=C.UTF-8 \
BUNDLE_JOBS=4 \
BUNDLE_RETRY=3
WORKDIR /usr/src/app
RUN gem install foreman
# Copy runtime Ruby dependencies and the precompiled assets from the builder stage
# COPY --from=builder /usr/local/bundle /usr/local/bundle
# COPY --from=builder /usr/src/app /usr/src/app
# COPY --from=watchman_builder /usr/local/bin/watchman /usr/local/bin/watchman
# COPY --from=watchman_builder /usr/local/bin/watchman-wait /usr/local/bin/watchman-wait
# RUN mkdir -p /usr/local/var/run/watchman \
# && touch /usr/local/var/run/watchman/.not-empty \
# && chmod 2777 /usr/local/var/run/watchman
# The entrypoint script is a good practice for handling Rails server startup
ENTRYPOINT ["./bin/docker-entrypoint-development"]
# Expose the application port
EXPOSE 3002
# Set the default command to run the Rails server
CMD ["./bin/dev"]
+5
View File
@@ -0,0 +1,5 @@
IF NOT EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE name = N'britton_dev_tools_dev')
BEGIN
CREATE DATABASE [britton_dev_tools_dev];
CREATE DATABASE [britton_dev_tools_test];
END;
+8
View File
@@ -0,0 +1,8 @@
Description:
Explain the generator
Example:
bin/rails generate legacy_db_model Thing
This will create:
what/will/it/create
@@ -0,0 +1,79 @@
class LegacyDbModelGenerator < Rails::Generators::Base
source_root File.expand_path('templates', __dir__)
argument :db_name, type: :string, required: true
argument :table_name, type: :string, required: true
def determine_db_record
if db_name == 'VHCS_HIPAA'
@db_record = 'VhcsRecord'.constantize
@module = 'Vhcs'.constantize
@file_folder = 'vhcs'
elsif db_name == 'HEBWeb'
@db_record = 'WebRecord'.constantize
@module = 'HebWeb'.constantize
@file_folder = 'heb_web'
else
raise LegacyDBModelError, "Invalid database, please use VHCS_HIPAA or HEBWeb"
end
end
def get_fields_if_table_exists
tn = table_name.strip
if @db_record.connection.table_exists?(tn) || @db_record.connection.view_exists?(table_name)
@fields = @db_record.connection.columns(tn).map { |col| col.name }
else
raise LegacyDBModelError, "Invalid table/view for #{db_name}, please double check spelling and capitalization"
end
end
# Add argurment for database, depending on db - change AR::Base below to correct db record
# Find out way to error out if table not found
# use this code to get table field names here, convert to underscore,
# send as aray or array pairs, and pass to template.
# columns = ActiveRecord::Base.connection.columns(table_name)
# field_names = columns.map(&:name)
def create_model_file
template "legacy_model.rb.erb.tt", "app/models/#{@file_folder}/#{file_name}.rb"
end
# kick off another schema dump and rebuild alt db schema
# Will need to persist what tables to run (maybe in db, maybe in alt db schema)
private
def file_name
"#{table_name.underscore}"
end
def class_name
"#{table_name.camelize}"
end
def uddt_type_mapping
{
"uddtBaseKey" => "integer, limit: 8",
"uddtIdPlan" => "string",
"uddtBaseEnum" => "uddt_base_enum",
"uddtBaseShortDesc" => "string",
"uddtBaseLongDesc" => "string",
"uddtBaseContact" => "string",
"uddtAddrCity" => "string",
"uddtAddrState" => "string",
"uddtAddrStreet" => "string",
"uddtAddrZip" => "string",
"uddtContPhone" => "string",
"uddtIdTax" => "string",
"uddtNotesNote" => "string",
"uddtFooter" => "string",
"uddtBaseDate" => "datetime",
"uddtBaseUserId" => "string"
}
end
class LegacyDBModelError < StandardError; end
end
@@ -0,0 +1,12 @@
module <%= @module %>
class <%= class_name %> < <%= @db_record %>
self.table_name = '<%= table_name %>'
<%- @fields.each do |fi| -%>
alias_attribute :<%= fi.underscore %>, :<%= fi %>
<%- end -%>
end
end
View File