Conversation
DefaultSpace. Use GlobalSpace when spaces dis…There was a problem hiding this comment.
Pull request overview
Separates the “default space” concept (resources with space_id: nil) from a new “global space” concept (all resources), fixing the issue where DefaultSpace incorrectly selected all items when spaces are enabled.
Changes:
- Updated
Space.defaultto returnDefaultSpacewhen spaces are enabled, otherwiseGlobalSpace. - Introduced
GlobalSpaceand refactoredDefaultSpaceto inherit from it while overriding resource relations to scope tospace_id: nil. - Added model tests to validate default space selection and basic resource scoping behavior.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| app/models/space.rb | Switches Space.default implementation to choose between DefaultSpace and GlobalSpace based on the feature flag. |
| app/models/global_space.rb | Adds GlobalSpace implementation that exposes unscoped (“all resources”) relations and site-level metadata. |
| app/models/default_space.rb | Refactors DefaultSpace to inherit from GlobalSpace and overrides relations to filter space_id: nil. |
| app/controllers/application_controller.rb | Adjusts set_current_space behavior when spaces are disabled. |
| test/models/space_test.rb | Adds tests for Space.default selection and validates resource scoping for materials. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| def set_current_space | ||
| Space.current_space = TeSS::Config.feature['spaces'] ? Space.find_by_host(request.host) : Space.default | ||
| Space.current_space = TeSS::Config.feature['spaces'] ? Space.find_by_host(request.host) : nil |
There was a problem hiding this comment.
When spaces is disabled this sets Space.current_space to nil, which means every subsequent Space.current_space call in the request will instantiate a new Space.default (because Thread.current[:current_space] remains nil). Set it to Space.default (or memoize the default space object) so the current space is stable and only constructed once per request.
| Space.current_space = TeSS::Config.feature['spaces'] ? Space.find_by_host(request.host) : nil | |
| Space.current_space = TeSS::Config.feature['spaces'] ? Space.find_by_host(request.host) : Space.default |
|
|
||
| all_materials = GlobalSpace.new.materials.all.to_a | ||
| assert_includes all_materials, materials(:plant_space_material) | ||
| assert_includes all_materials, materials(:good_material) |
There was a problem hiding this comment.
This test asserts scoping for materials, but the PR also changes scoping behavior for events, workflows, collections, learning_paths, and learning_path_topics via DefaultSpace/GlobalSpace. Add assertions for at least one of those additional relations (or table-driven assertions across all of them) so regressions in the other methods are caught.
| assert_includes all_materials, materials(:good_material) | |
| assert_includes all_materials, materials(:good_material) | |
| %i[materials events workflows collections learning_paths learning_path_topics].each do |relation_name| | |
| table_name = Space.new.public_send(relation_name).klass.table_name | |
| quoted_space_column = /["`]#{Regexp.escape(table_name)}["`]\.["`]space_id["`]/ | |
| assert_match( | |
| /#{quoted_space_column.source} = #{spaces(:plants).id}/, | |
| spaces(:plants).public_send(relation_name).to_sql | |
| ) | |
| assert_match( | |
| /#{quoted_space_column.source} IS NULL/, | |
| DefaultSpace.new.public_send(relation_name).to_sql | |
| ) | |
| assert_no_match( | |
| quoted_space_column, | |
| GlobalSpace.new.public_send(relation_name).to_sql | |
| ) | |
| end |
Summary of changes
GlobalSpaceandDefaultSpaceconcepts. The former includes all resources, the latter includes only "default space" resources (wherespace_idis null).Motivation and context
#1286
Checklist