• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

MushroomObserver / mushroom-observer / 26632367492
97%

Build:
DEFAULT BRANCH: main
Ran 29 May 2026 10:37AM UTC
Jobs 1
Files 1036
Run time 2min
Badge
Embed ▾
README BADGES
x

If you need to use a raster PNG badge, change the '.svg' to '.png' in the link

Markdown

Textile

RDoc

HTML

Rst

29 May 2026 10:33AM UTC coverage: 96.508%. Remained the same
26632367492

push

github

web-flow
SpeciesList: sync_projects on the model; controller becomes a thin caller (#4390)

Moves the per-project add/remove logic from
`SpeciesListsController#update_projects` (+ its `change_project_species_lists`
helper) into a new `SpeciesList#sync_projects(submitted_project_ids,
user:)` method. The controller stays in charge of `flash_notice` (which
the model has no business doing) but the relationship logic — what's
"desired" vs. "current," which projects are even toggleable for the
given user, mutating the join through `Project#add_species_list` /
`#remove_species_list` — now lives on the model where it can be
unit-tested directly.

```ruby
# In SpeciesList:
def sync_projects(submitted_project_ids, user:)
  # Returns [[project, :added | :removed], …] for the caller to flash.
end

# In SpeciesListsController:
def update_projects(spl, submitted_ids)
  changes = spl.sync_projects(submitted_ids, user: @user)
  changes.each { |project, change| flash_project_change(project, change) }
  return if changes.empty?

  flash_notice(:species_list_show_manage_observations_too.t)
end
```

`change_project_species_lists` (the per-change flash + mutation helper)
deletes; the per-change flash collapses into a tiny
`flash_project_change(project, change)`.

Net diff: controller -32 lines, model +34 lines, tests +70 lines.

## Why

Two reasons.

1. Pulling the relationship logic off the controller stops the
   controller from quietly growing every time we need to nudge how
   project sync works. The controller was already at
   `# rubocop:disable Metrics/ClassLength` after #4389; this trims a
   bit and pushes future changes to the right place.
2. Testing the sync semantics from the controller required hitting
   the full HTTP flow (login, params, flash assertions). On the model
   it's straight-up `list.sync_projects([id.to_s], user: user)`
   followed by `assert_includes(list.reload.projects, project)`. The
   5 new model tests cover: nil submission (no-op),
   empty-submis... (continued)

22 of 22 new or added lines in 2 files covered. (100.0%)

39521 of 40951 relevant lines covered (96.51%)

671.36 hits per line

Jobs
ID Job ID Ran Files Coverage
1 26632367492.1 29 May 2026 10:37AM UTC 1036
96.51
GitHub Action Run
Source Files on build 26632367492
  • Tree
  • List 1036
  • Changed 2
  • Source Changed 2
  • Coverage Changed 2
Coverage ∆ File Lines Relevant Covered Missed Hits/Line
  • Back to Repo
  • Github Actions Build #26632367492
  • 92191aff on github
  • Prev Build on main (#26631317870)
  • Next Build on main (#26632455807)
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc