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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions app/models/company.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ class Company < ApplicationRecord
has_many :opportunities, dependent: :destroy
has_many :resource_sheets, dependent: :nullify

before_validation :normalize_name
before_save :shorten_urls, :sanitize_size

# Validations
validates :name, presence: true
validates :name, uniqueness: { case_sensitive: false }
validates :company_type, inclusion: { in: %w[Product Consultancy Staffing], message: "%{value} is not a valid company type" }, allow_nil: true
validates :size, format: { with: /\A[\d,\-\s]*\z/, message: "should be a range like '501-1,000'" }, allow_nil: true, allow_blank: true

Expand Down Expand Up @@ -64,6 +66,10 @@ def tech_stack_with_sources

private

def normalize_name
self.name = name.to_s.squish.presence
end

def shorten_urls
if website_changed? && website.present? && !website.include?("is.gd")
shortened = UrlShortenerService.shorten(website)
Expand Down
28 changes: 28 additions & 0 deletions db/migrate/20260310120000_add_unique_index_on_companies_name.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class AddUniqueIndexOnCompaniesName < ActiveRecord::Migration[8.0]
def up
execute <<~SQL
UPDATE companies
SET name = NULLIF(TRIM(REGEXP_REPLACE(name, '\\s+', ' ', 'g')), '')
WHERE name IS NOT NULL;
SQL

duplicate_names = select_values(<<~SQL)
SELECT LOWER(name)
FROM companies
WHERE name IS NOT NULL
GROUP BY LOWER(name)
HAVING COUNT(*) > 1
SQL

if duplicate_names.any?
raise ActiveRecord::IrreversibleMigration,
"Cannot add unique index on companies.name. Resolve duplicates first: #{duplicate_names.join(', ')}"
end

add_index :companies, "LOWER(name)", unique: true, name: "index_companies_on_lower_name"
end

def down
remove_index :companies, name: "index_companies_on_lower_name"
end
end
28 changes: 28 additions & 0 deletions spec/models/company_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require "rails_helper"

RSpec.describe Company, type: :model do
describe "validations" do
it "validates name presence" do
company = Company.new(name: nil, company_type: "Product")

expect(company).not_to be_valid
expect(company.errors[:name]).to include("can't be blank")
end

it "validates name uniqueness case-insensitively" do
Company.create!(name: "Acme Corp", company_type: "Product")
duplicate = Company.new(name: "acme corp", company_type: "Product")

expect(duplicate).not_to be_valid
expect(duplicate.errors[:name]).to include("has already been taken")
end

it "normalizes whitespace in name before validation" do
company = Company.new(name: " New Co ", company_type: "Product")

company.validate

expect(company.name).to eq("New Co")
end
end
end
Loading