Store school email domains#787
Conversation
There was a problem hiding this comment.
Pull request overview
Introduces first-class storage for school email domains by adding a dedicated table/model and wiring it into the School domain model, with accompanying specs.
Changes:
- Added
school_email_domainstable with a composite unique index per school. - Added
SchoolEmailDomainmodel withbefore_validationnormalization (strip leading@, downcase). - Updated
Schooltohas_many :school_email_domainsand added/updated model specs.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| spec/models/school_spec.rb | Adds association + dependent-destroy coverage for school_email_domains. |
| spec/models/school_email_domain_spec.rb | Adds model spec coverage for domain normalization behavior. |
| db/schema.rb | Reflects new school_email_domains table and foreign key. |
| db/migrate/20260420104937_create_school_email_domains.rb | Creates the new school_email_domains table and composite unique index. |
| app/models/school_email_domain.rb | Introduces the new model and domain normalization callback. |
| app/models/school.rb | Adds has_many :school_email_domains, dependent: :destroy. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Add a migration to create the school_email_domains table, storing a domain string against a school_id
Create the model and add initial specs
Removing leading @ symbols and lower case domains
4740867 to
aff003a
Compare
Test coverage89.5% line coverage reported by SimpleCov. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
fspeirs
left a comment
There was a problem hiding this comment.
Overall this looks like the right approach. I have one consideration about validating domains - I feel like it would be helpful to be stricter in checking that the user hasn't typo'ed their domain or misunderstood what we are asking for.
fspeirs
left a comment
There was a problem hiding this comment.
Directionally, quite correct. Just some sharpening of the normalisation approach in school_email_domain and a request for a testing method in school.rb. The lack of a testing method is non-blocking if it's coming in a separate PR.
| def normalise_domain | ||
| return if domain.nil? | ||
|
|
||
| self.domain = build_normalised_domain_string(domain) | ||
| end |
There was a problem hiding this comment.
Issue: I think this code could be much simpler and doesn't have to expressly handle specific things like uri_host_if_http_url. Instead, I suggest that we just try to parse a URI and, if successful take the host portion:
def normalise_domain
return if domain.blank?
value = domain.strip.downcase
# Add a scheme unless it already has one, so URI can parse it
value = "http://#{value}" unless value =~ %r{\A[a-z][a-z0-9+\-.]*://}i
uri = URI.parse(value)
host = uri.host
return if host.blank?
if PublicSuffix.valid?(host)
self.domain = host
else
errors.add(:domain, "is not a valid domain")
end
rescue URI::InvalidURIError
errors.add(:domain, "is not a valid domain")
endThis is kind of the approach you're taking in uri_host_if_http_url and pulling it up to be the main way we normalise domains: (a) can we parse it with URI::parse and secondly is it a valid suffix.
| has_many :projects, dependent: :nullify | ||
| has_many :roles, dependent: :nullify | ||
| has_many :school_projects, dependent: :nullify | ||
| has_many :school_email_domains, dependent: :destroy |
There was a problem hiding this comment.
Issue: Callers (including my work) would like a validator method on this called something like: valid_domain?(candidate_domain) which returns true if candidate_domain is registered for this school.
This would allow testing domains presented by registering users without exposing the internal implementation of school_email_domains.
Status
Closes #1325
What's changed?
school_email_domainstableSchoolEmailDomainmodelSchool