Skip to content

Discovery: store and return Scratch data#720

Merged
mwtrew merged 15 commits intomainfrom
1130_store-and-return-scratch-data
Mar 16, 2026
Merged

Discovery: store and return Scratch data#720
mwtrew merged 15 commits intomainfrom
1130_store-and-return-scratch-data

Conversation

@mwtrew
Copy link
Contributor

@mwtrew mwtrew commented Mar 9, 2026

Status

Points for consideration:

See the ADR for performance and security implications.

What's changed?

  • Enables creation, saving and loading of Scratch project files (project.json). Does not yet enable these for assets.

Rather than using the existing Component model, this adds a new Scratch
component model. Projects expect to be able to update project metadata
and component data at the same time, however for Scratch the lifecycle
of project.json is managed independently by scratch-gui so it's best
to keep that separate.
@cla-bot cla-bot bot added the cla-signed label Mar 9, 2026
@github-actions
Copy link

github-actions bot commented Mar 9, 2026

Test coverage

89.61% line coverage reported by SimpleCov.
Run: https://github.com/RaspberryPiFoundation/editor-api/actions/runs/23145670774

@mwtrew mwtrew changed the title Add Scratch component model Discovery: store and return Scratch data Mar 9, 2026
mwtrew and others added 6 commits March 10, 2026 09:09
Only SVGs are working at present, as non-text formats like PNG are not
recognised due to Scratch sending the incorrect content type header.

Further work needed to support other file types.
This reverts commit 6d4d4bc.

This was only partially working, we will revisit it in a subsequent PR.
@mwtrew mwtrew marked this pull request as ready for review March 12, 2026 13:42
Copilot AI review requested due to automatic review settings March 12, 2026 13:42
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds persistence for Scratch project.json by introducing a ScratchComponent model/table associated to Project, and wiring up API endpoints/tests to load and save that JSON content.

Changes:

  • Add scratch_components table + ScratchComponent model and Project#scratch_component association.
  • Update project creation / permitted params to accept and build scratch component data.
  • Implement /api/scratch/projects/:id show/update endpoints and request specs.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
app/controllers/api/scratch/scratch_controller.rb Adds shared load_project before-action for Scratch API controllers.
app/controllers/api/scratch/projects_controller.rb Switches Scratch project show to return stored JSON and adds update to persist JSON.
app/models/project.rb Introduces has_one :scratch_component and assignment helper.
app/models/scratch_component.rb New AR model for storing Scratch JSON.
db/migrate/20260309104851_create_scratch_components.rb Migration creating scratch_components table.
db/schema.rb Schema update reflecting new table + FK.
lib/concepts/project/operations/create.rb Extends project creation to build a scratch component.
app/controllers/api/projects_controller.rb Permits scratch_component in project params.
app/controllers/api/lessons_controller.rb Permits scratch_component within nested project_attributes.
app/graphql/mutations/create_project.rb Passes scratch_component through to Project::Create.
spec/factories/scratch_components.rb Adds factory for scratch components with default JSON shape.
spec/features/scratch/showing_a_scratch_project_spec.rb Updates show spec to create real project + scratch component.
spec/features/scratch/updating_a_scratch_project_spec.rb Updates update spec to persist scratch content and assert DB write.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

end

def update
@project.scratch_component&.content = params
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@project.scratch_component&.content = params will persist framework/routing keys like controller, action, id, and potentially other untrusted request keys into content, which will then be echoed back by show. Extract and persist only the Scratch project payload (e.g., params.require(:content) or a permitted subset like targets/monitors/extensions/meta) and convert to a plain Hash before assignment.

Suggested change
@project.scratch_component&.content = params
scratch_content = params.require(:content)
@project.scratch_component&.content = scratch_content.to_unsafe_h

Copilot uses AI. Check for mistakes.
end

def update
@project.scratch_component&.content = params
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to note that I can't see any authorization checks on the project to make sure the user is allowed to write to it.

This doesn't have to be done as part of this PR, but we should make sure there's an issue for it if not.

We can't add auth to the show action yet (but I am coming up with a proposal for that)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, expecting this to be handled in a separate ticket.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please make sure it's covered by an issue (by adding it to one or creating a new one) - I don't want it to be lost.

Copy link
Contributor

@zetter-rpf zetter-rpf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, I've left a few comments and I saw you're looking at the copilot ones, let me know when they are resolved and I can approve.

mwtrew added 5 commits March 16, 2026 08:20
This avoids missing errors.
In the update case it won't matter, and in the show case an error would be better than nil.
This reverts commit e8b84ee.

This causes an "unoptimised query" error that I'd rather not dive into
just now.
zetter-rpf
zetter-rpf previously approved these changes Mar 16, 2026
Copy link
Contributor

@zetter-rpf zetter-rpf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work!

@mwtrew mwtrew merged commit 3c12216 into main Mar 16, 2026
6 checks passed
@mwtrew mwtrew deleted the 1130_store-and-return-scratch-data branch March 16, 2026 13:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants