* Improve read performance with caching and memoization
- Memoize `Crop#all_companions` and `Member#unread_count` in models
- Implement instance-level memoization in `CropsHelper#crop_or_parent`
- Add Rails caching for expensive aggregate queries in `Charts::CropsController`
- Add fragment caching for high-impact sections on the crop show page
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
* Fix header spec failure due to memoized unread_count
- Reset `@unread_count` in `spec/views/layouts/_header_spec.rb` to ensure the updated notification count is rendered correctly.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* Update planting rating when recording a harvest
- Added virtual attribute `overall_rating` to `Harvest` model.
- Updated `HarvestsController` to permit `overall_rating` and synchronize it to the associated `Planting`.
- Added a rating range field (1-5) to the harvest form.
- Added controller tests to verify that the planting rating is updated.
- Refined feature tests for harvesting.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
* I have updated the system to allow for recording a planting rating when a harvest is logged. Here is a summary of the changes:
- Added a virtual attribute `overall_rating` to the `Harvest` model.
- Updated `HarvestsController` to permit `overall_rating` and synchronize it to the associated `Planting`.
- Added a rating range field (1-5) to the harvest form.
- Added controller tests to verify that the planting rating is updated correctly.
- Updated feature tests to ensure the harvest form functions as expected.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
* Update database.yml
* Apply suggestions from code review
Co-authored-by: Daniel O'Connor <daniel.oconnor@gmail.com>
* Adjust wording
* Change harvest modal
* Fix tests
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
- Added `send_harvest_reminder` preference to Member model and settings UI.
- Implemented `harvest_in_next_week?` in PredictHarvest concern.
- Created `harvest_reminder` email with localized templates.
- Added `growstuff:send_harvest_reminders` Rake task to run weekly.
- Refactored existing and new reminder tasks to use `deliver_later` for scalability.
- Added unit tests for prediction logic and mailer.
- Fixed a bug in the existing planting reminder task where it was using an uninitialized constant `Notifier`.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
* Refactor Activity model to remove Elasticsearch integration
- Removed `SearchActivities` concern and Searchkick from `Activity` model.
- Implemented `Activity.homepage_records` using ActiveRecord with `DISTINCT ON` for PostgreSQL.
- Updated `ActivitiesController#index` to use ActiveRecord queries with eager loading and pagination.
- Added `active` scope to `Activity`.
- Added unit tests for `Activity` model.
- Deleted `app/models/concerns/search_activities.rb`.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
* Fix NoMethodError: undefined method 'reindex' for class Activity
- Removed all calls to `Activity.reindex` in migrations, rake tasks, and spec helpers.
- These were causing failures after the removal of Searchkick from the Activity model.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
* Fix ambiguous column id in homepage_records query
- Updated `Activity.homepage_records` to use `activities.id` instead of `id` in the subquery.
- This resolves the `PG::AmbiguousColumn: ERROR: column reference "id" is ambiguous` error.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
* Fix ambiguous created_at in homepage_records query
- Use `unscoped` in the subquery for `Activity.homepage_records` to bypass the default scope from `Ownable` concern.
- This prevents the join with the `members` table in the subquery, which was causing `PG::AmbiguousColumn: ERROR: column reference "created_at" is ambiguous`.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
* Complete refactoring of Activity model to remove Elasticsearch
- Removed SearchActivities concern and searchkick integration.
- Updated ActivitiesController#index to use ActiveRecord queries.
- Implemented performant Activity.homepage_records using DISTINCT ON (PostgreSQL).
- Added Activity.active scope.
- Added no-op Activity.reindex (class and instance methods) for backward compatibility.
- Cleaned up leftover reindex calls in rake tasks, migrations, and spec helpers.
- Added unit tests for new Activity model logic.
- Updated factories to include no-op reindex traits.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
* Less eager loading
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This commit introduces memoization to various methods in the Planting model,
PredictPlanting and PredictHarvest concerns, PlantingsHelper, and
PlantingsController.
Specifically:
- Memoized database-intensive lookups like `nearby_same_crop`, `first_harvest_date`,
and `last_harvest_date`.
- Memoized calculated fields like `finish_predicted_at`, `expected_lifespan`,
and `age_in_days`.
- Optimized `PlantingsHelper#transplantable_gardens_by_owner` using a hash
to cache results per planting instance within a request.
- Applied the `defined?(@variable)` pattern where appropriate to ensure
efficient handling of `nil` results.
These changes reduce redundant database queries and expensive calculations,
particularly during view rendering where these methods are frequently accessed.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
- Update MemberFlickr concern to support tag-based search using flickr.photos.search
- Update PhotosController to handle the 'tag' parameter
- Add tag search input field to the 'New Photo' view
- Add test case to verify tag filtering in PhotosController spec
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
- Memoize display methods in `Harvest` model.
- Memoize calculation methods in `PredictHarvest` concern using `defined?` for nil safety.
- Add fragment caching to `app/views/harvests/_popover.html.haml`.
- Add fragment caching to `app/views/crops/_harvests.html.haml` with daily expiration for relative time strings.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
* Add members:cleanup_inactive rake task
This task identifies and deletes members who have not logged in for over
24 months and have no gardens, plantings, or other activity (posts,
comments, seeds, harvests, etc).
Includes support for DRY_RUN=true to preview deletions.
Added tests in spec/tasks/members_spec.rb.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
* Refactor activity check to Member#has_activity? and update rake task
- Added `Member#has_activity?` to encapsulate the check for gardens, plantings, and other activity.
- Updated `members:cleanup_inactive` rake task to use `Member#has_activity?`.
- Maintained `DRY_RUN` support and existing tests.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
* Apply suggestion from @CloCkWeRX
* Apply suggestions from code review
Co-authored-by: Daniel O'Connor <daniel.oconnor@gmail.com>
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
* Implement blocking feature
This commit introduces a blocking feature that allows members to block other members.
A blocked member is prevented from:
- following the blocker
- sending private messages to the blocker
- replying to the blocker's posts
- liking the blocker's content
The implementation includes:
- A new `Block` model and a corresponding database table.
- Updates to the `Member` model to include associations for blocks.
- A new `BlocksController` to handle blocking and unblocking actions.
- New routes for the `BlocksController`.
- UI changes to add block/unblock buttons to the member profile page.
- Validations in the `Follow`, `Comment`, and `Like` models to enforce the blocking rules.
- A check in the `MessagesController` to prevent sending messages to a member who has blocked the sender.
- A callback in the `Block` model to destroy the follow relationship when a block is created.
- New feature and model specs to test the blocking functionality.
* Implement blocking feature and fix failing tests
This commit introduces a blocking feature that allows members to block other members.
A blocked member is prevented from:
- following the blocker
- sending private messages to the blocker
- replying to the blocker's posts
- liking the blocker's content
The implementation includes:
- A new `Block` model and a corresponding database table.
- Updates to the `Member` model to include associations for blocks.
- A new `BlocksController` to handle blocking and unblocking actions.
- New routes for the `BlocksController`.
- UI changes to add block/unblock buttons to the member profile page.
- Validations in the `Follow`, `Comment`, and `Like` models to enforce the blocking rules.
- A check in the `MessagesController` to prevent sending messages to a member who has blocked the sender.
- A callback in the `Block` model to destroy the follow relationship when a block is created.
- New feature and model specs to test the blocking functionality.
This commit also fixes a failing test in the blocking feature. The error was caused by the validation being called even when the `member` association was `nil`. A guard has been added to the validation methods in the `Like`, `Follow`, and `Comment` models to prevent this from happening.
* Generate schema
* Fix tests
* Add permissions
* Define Block permissions in Ability model
The feature specs for member blocking were failing because the "Block"
link was not being rendered on member profiles. This was due to the
lack of explicit create and destroy permissions for the Block resource
in the Ability model, which is used by CanCanCan to authorize actions
and by the view to conditionally show links.
This change adds the necessary permissions to `member_abilities`:
- Allows members to create blocks (except for blocking themselves).
- Allows members to destroy blocks where they are the blocker.
These rules ensure that the "Block" and "Unblock" links are correctly
rendered and authorized for signed-in members.
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
* Comment out specs for now
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: Daniel O'Connor <daniel.oconnor@gmail.com>
Co-authored-by: CloCkWeRX <365751+CloCkWeRX@users.noreply.github.com>
This commit introduces a new partial to display nutritional data from the Australian Food Composition Database.
Key changes:
- Adds a database index to the `public_food_key` on the `crops` table.
- Establishes a `has_one` relationship between `Crop` and `AustralianFoodClassificationData`.
- Creates a `_nutritional_data.html.haml` partial to display a summary of key nutritional information.
- Renders the partial on the `show` pages for both crops and harvests.
* feat: Add version tracking to Crop model
This commit introduces version tracking for the Crop model using the PaperTrail gem.
Key changes include:
- Integrating `has_paper_trail` into the `Crop` model.
- Adding a "History" section to the crop show page to display a timeline of changes for that specific crop.
- Creating a new admin page for users with the "crop_wrangler" role to view a log of all recent crop edits, creations, and deletions.
- Fixing several N+1 query performance issues by eager-loading associated `Member` records in both the `CropsController` and the new `Admin::CropsController`.
- Refactoring view logic into a shared partial to reduce code duplication.
* Add papertrail
* Admin UI
* Add papertrail DB
* Add papertrail DB
* Rearrange
* Fix permissions
* Fix permissions
* Fix UI
* Fix UI
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: Daniel O'Connor <daniel.oconnor@gmail.com>
I have added a new test to `spec/models/crop_spec.rb` to verify that deleting a crop also destroys the associated `CropCompanion` records.
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This change migrates the crop description from the `openfarm_data` JSONB field to a new, dedicated `description` text column in the `crops` table.
A data migration is included to move the existing description data to the new column. The `OpenFarmData` concern is updated to remove the now-redundant `description` method.
This commit introduces the following changes:
- Adds an `en_youtube_url` attribute to the `Crop` model to store a URL for an English language YouTube video.
- If a `en_youtube_url` is present for a crop, the video is embedded on the crop's show page.
- A link is added to the "Learn more" section of the crop's show page to search YouTube for "growing [crop name]".
- A helper method is added to extract the video ID from various YouTube URL formats.
- A validation is added to the `Crop` model to ensure that the `en_youtube_url` is a valid YouTube URL.
This change adds the ability for crop wranglers to create and manage companion plantings for crops.
- Adds a `source_url` to the `CropCompanion` model to store an optional reference URL.
- Restricts the management of companion plantings to users with the `crop_wrangler` role.
- Creates a new admin interface for managing companion plantings for a specific crop.
- Updates the crop show page to display companions from both the crop and its parent crop.
* feat: Add API token generation and authentication
This commit introduces API token generation and authentication for write operations.
- Adds a section to the user's profile edit page to generate and display an API token.
- Reuses the `authentications` table to store the API token, avoiding the need for a database migration.
- Implements token-based authentication for the API using the `Authorization: Token token=...` header.
- Enables write operations for all API resources and ensures they are protected by the new authentication mechanism.
- Adds feature and request specs to test the new functionality.
* feat: Add API token generation and authentication
This commit introduces API token generation and authentication for write operations.
- Adds a section to the user's profile edit page to generate and display an API token.
- Reuses the `authentications` table to store the API token, avoiding the need for a database migration.
- Implements token-based authentication for the API using the `Authorization: Token token=...` header.
- Enables write operations for all API resources and ensures they are protected by the new authentication mechanism.
- Adds feature and request specs to test the new functionality.
* Mark as editable
* Refactor
* WIP - Authentication
* Implement more test coverage
* Split 401 and 403
* Before Create hooks
* Update harvest specs, defaulting to the first plant part - this may not be right
* Update coverage
* Update coverage
* Rubocop
* Rubocop
* Rubocop
* Fix coverage
* For now, mark photos immutable again
* Fix specs
* Fix specs
* Rubocop
* Fix specs
---------
Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
Co-authored-by: Daniel O'Connor <daniel.oconnor@gmail.com>