Dep upgrades; bug fixes

This commit is contained in:
Dan Elbert 2026-04-20 13:46:42 -05:00
parent 28baaa3c3d
commit df99f800b9
16 changed files with 347 additions and 262 deletions

View File

@ -7,3 +7,4 @@ public/packs
node_modules/ node_modules/
.yarn .yarn
.pnp.* .pnp.*
.claude

1
.gitignore vendored
View File

@ -37,3 +37,4 @@ yarn-debug.log*
.yarn-integrity .yarn-integrity
.yarn .yarn
.pnp.* .pnp.*
.claude

View File

@ -1 +1 @@
3.3.5 4.0.2

73
CLAUDE.md Normal file
View File

@ -0,0 +1,73 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
Parsley is a personal recipe manager and meal planning app. It is a monolithic Rails 7.2 application with a Vue 3 SPA frontend.
**Backend:** Ruby 4.0.2, Rails 8.1.3, SQLite (dev/test), PostgreSQL (production)
**Frontend:** Vue 3 (Composition API / `<script setup>`), Pinia, Vue Router 4, Bulma CSS
**Asset bundling:** Shakapacker 8 (Webpack 5 + SWC)
**Testing:** RSpec, FactoryBot, Guard
## Common Commands
```bash
# Development
foreman start # Start Rails + Shakapacker dev server together
# Dependencies
bundle install && yarn install
# Database
bundle exec rake db:create db:migrate db:seed
bundle exec rake db:reset # Drop, recreate, seed
# Tests
bundle exec rspec # All tests
bundle exec rspec spec/models/recipe_spec.rb # Single file
bundle exec rspec spec/models/recipe_spec.rb:42 # Single test by line
bundle exec guard # Watch mode
# Build
bundle exec rake shakapacker:compile # Compile assets for production
```
**Test environment note:** Set `FAST=true` to skip FactoryBot linting on startup.
## Architecture
### Backend
**Models follow an `Ingredient` abstraction:** `Recipe` and `Food` both inherit from an abstract `Ingredient` base class. This allows recipes to contain both foods and other recipes as ingredients (`RecipeIngredient` is a polymorphic join). Polymorphic ingredient IDs are encoded as strings: `F{id}` for foods, `R{id}` for recipes.
**Custom unit conversion library** (`lib/unit_conversion/`): The `UnitConversion` module handles all quantity parsing and conversion. It is density-aware (can convert volume ↔ mass if food density is known) and supports custom per-food units defined in `FoodUnit` records. Key entry points: `UnitConversion.parse`, `UnitConversion.auto_unit`, `UnitConversion.with_custom_units`.
**Recipe scaling:** Recipes can be scaled by a factor and converted between unit systems (standard/metric) and unit types (mass/volume). Cache keys incorporate scale and unit system: `recipes/{id}/{scale}/{system}/{unit}`. Memcache is optional; enable with `RAILS_USE_MEMCACHE=true`.
**USDA nutrition data:** The `UsdaImporter` (lib/) imports from `vendor/data/usda/` during `db:seed`. `UsdaFood`/`UsdaFoodWeight` tables are a read-only cache; `Food` records link to them and inherit nutritional data.
**Serializers** (`app/serializers/`) handle all JSON API responses.
### Frontend
Vue 3 components live in `app/javascript/components/`. They use `<script setup>` Composition API style. Pinia stores (`app/javascript/stores/`) hold global state. Vue Router (`app/javascript/router/`) manages navigation.
Page-level components are named `The*` (e.g., `TheRecipeList`, `TheFood`, `TheCalculator`). Shared UI primitives are named `App*` (e.g., `AppModal`, `AppAutocomplete`, `AppIcon`).
### Key Environment Variables
| Variable | Purpose |
|----------|---------|
| `RAILS_USE_MEMCACHE` | Enable Memcache caching |
| `RAILS_MEMCACHE_HOST` | Memcache host (default: `memcache`) |
| `PARSLEY_DB_HOST/USER/PG_PASSWORD/DB_NAME` | Production PostgreSQL config |
### Docker
`docker-compose up` starts PostgreSQL, Memcached, Nginx, and two Rails service instances. See `docker-compose.yml` and `Dockerfile`.
### Seed Data
Default dev user: username `dan`, password `qwerty`. Comes with sample recipes and foods.

View File

@ -1,8 +1,9 @@
FROM ruby:3.3.5-bookworm FROM ruby:4.0.2-trixie
RUN curl -sL https://deb.nodesource.com/setup_lts.x | bash - && \ RUN curl -sL https://deb.nodesource.com/setup_lts.x | bash - && \
apt-get update && apt-get dist-upgrade -y && \ apt-get update && apt-get dist-upgrade -y && \
apt-get install -y \ apt-get install -y \
pkg-config \
nodejs \ nodejs \
nginx && \ nginx && \
apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/*

View File

@ -1,6 +1,6 @@
source 'https://rubygems.org' source 'https://rubygems.org'
gem 'rails', '7.2.1' gem 'rails', '8.1.3'
gem 'pg', '~> 1.5.8' gem 'pg', '~> 1.5.8'
gem 'shakapacker', '8.0.2' gem 'shakapacker', '8.0.2'

View File

@ -1,106 +1,112 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (7.2.1) action_text-trix (2.1.18)
actionpack (= 7.2.1) railties
activesupport (= 7.2.1) actioncable (8.1.3)
actionpack (= 8.1.3)
activesupport (= 8.1.3)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (>= 0.6.1) websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
actionmailbox (7.2.1) actionmailbox (8.1.3)
actionpack (= 7.2.1) actionpack (= 8.1.3)
activejob (= 7.2.1) activejob (= 8.1.3)
activerecord (= 7.2.1) activerecord (= 8.1.3)
activestorage (= 7.2.1) activestorage (= 8.1.3)
activesupport (= 7.2.1) activesupport (= 8.1.3)
mail (>= 2.8.0) mail (>= 2.8.0)
actionmailer (7.2.1) actionmailer (8.1.3)
actionpack (= 7.2.1) actionpack (= 8.1.3)
actionview (= 7.2.1) actionview (= 8.1.3)
activejob (= 7.2.1) activejob (= 8.1.3)
activesupport (= 7.2.1) activesupport (= 8.1.3)
mail (>= 2.8.0) mail (>= 2.8.0)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
actionpack (7.2.1) actionpack (8.1.3)
actionview (= 7.2.1) actionview (= 8.1.3)
activesupport (= 7.2.1) activesupport (= 8.1.3)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
racc rack (>= 2.2.4)
rack (>= 2.2.4, < 3.2)
rack-session (>= 1.0.1) rack-session (>= 1.0.1)
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
useragent (~> 0.16) useragent (~> 0.16)
actiontext (7.2.1) actiontext (8.1.3)
actionpack (= 7.2.1) action_text-trix (~> 2.1.15)
activerecord (= 7.2.1) actionpack (= 8.1.3)
activestorage (= 7.2.1) activerecord (= 8.1.3)
activesupport (= 7.2.1) activestorage (= 8.1.3)
activesupport (= 8.1.3)
globalid (>= 0.6.0) globalid (>= 0.6.0)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
actionview (7.2.1) actionview (8.1.3)
activesupport (= 7.2.1) activesupport (= 8.1.3)
builder (~> 3.1) builder (~> 3.1)
erubi (~> 1.11) erubi (~> 1.11)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
activejob (7.2.1) activejob (8.1.3)
activesupport (= 7.2.1) activesupport (= 8.1.3)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (7.2.1) activemodel (8.1.3)
activesupport (= 7.2.1) activesupport (= 8.1.3)
activerecord (7.2.1) activerecord (8.1.3)
activemodel (= 7.2.1) activemodel (= 8.1.3)
activesupport (= 7.2.1) activesupport (= 8.1.3)
timeout (>= 0.4.0) timeout (>= 0.4.0)
activestorage (7.2.1) activestorage (8.1.3)
actionpack (= 7.2.1) actionpack (= 8.1.3)
activejob (= 7.2.1) activejob (= 8.1.3)
activerecord (= 7.2.1) activerecord (= 8.1.3)
activesupport (= 7.2.1) activesupport (= 8.1.3)
marcel (~> 1.0) marcel (~> 1.0)
activesupport (7.2.1) activesupport (8.1.3)
base64 base64
bigdecimal bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1) concurrent-ruby (~> 1.0, >= 1.3.1)
connection_pool (>= 2.2.5) connection_pool (>= 2.2.5)
drb drb
i18n (>= 1.6, < 2) i18n (>= 1.6, < 2)
json
logger (>= 1.4.2) logger (>= 1.4.2)
minitest (>= 5.1) minitest (>= 5.1)
securerandom (>= 0.3) securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5) tzinfo (~> 2.0, >= 2.0.5)
base64 (0.2.0) uri (>= 0.13.1)
bcrypt (3.1.20) base64 (0.3.0)
bigdecimal (3.1.8) bcrypt (3.1.22)
bootsnap (1.18.4) bigdecimal (4.1.2)
bootsnap (1.23.0)
msgpack (~> 1.2) msgpack (~> 1.2)
builder (3.3.0) builder (3.3.0)
coderay (1.1.3) coderay (1.1.3)
concurrent-ruby (1.3.4) concurrent-ruby (1.3.6)
connection_pool (2.4.1) connection_pool (3.0.2)
crass (1.0.6) crass (1.0.6)
csv (3.3.0) csv (3.3.5)
dalli (3.2.8) dalli (3.2.8)
database_cleaner (2.0.2) database_cleaner (2.0.2)
database_cleaner-active_record (>= 2, < 3) database_cleaner-active_record (>= 2, < 3)
database_cleaner-active_record (2.2.0) database_cleaner-active_record (2.2.2)
activerecord (>= 5.a) activerecord (>= 5.a)
database_cleaner-core (~> 2.0.0) database_cleaner-core (~> 2.0)
database_cleaner-core (2.0.1) database_cleaner-core (2.0.1)
date (3.3.4) date (3.5.1)
diff-lcs (1.5.1) diff-lcs (1.6.2)
drb (2.2.1) drb (2.2.3)
erubi (1.13.0) erb (6.0.3)
factory_bot (6.5.0) erubi (1.13.1)
activesupport (>= 5.0.0) factory_bot (6.5.6)
factory_bot_rails (6.4.3) activesupport (>= 6.1.0)
factory_bot (~> 6.4) factory_bot_rails (6.4.4)
factory_bot (~> 6.5)
railties (>= 5.0.0) railties (>= 5.0.0)
ffi (1.17.0) ffi (1.17.4)
formatador (1.1.0) formatador (1.2.3)
globalid (1.2.1) reline
globalid (1.3.0)
activesupport (>= 6.1) activesupport (>= 6.1)
guard (2.18.1) guard (2.18.1)
formatador (>= 0.2.4) formatador (>= 0.2.4)
@ -116,12 +122,15 @@ GEM
guard (~> 2.1) guard (~> 2.1)
guard-compat (~> 1.1) guard-compat (~> 1.1)
rspec (>= 2.99.0, < 4.0) rspec (>= 2.99.0, < 4.0)
i18n (1.14.6) i18n (1.14.8)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
io-console (0.7.2) io-console (0.8.2)
irb (1.14.1) irb (1.17.0)
pp (>= 0.6.0)
prism (>= 1.3.0)
rdoc (>= 4.0.0) rdoc (>= 4.0.0)
reline (>= 0.4.2) reline (>= 0.4.2)
json (2.19.4)
kaminari (1.2.2) kaminari (1.2.2)
activesupport (>= 4.1.0) activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.2) kaminari-actionview (= 1.2.2)
@ -135,124 +144,136 @@ GEM
kaminari-core (= 1.2.2) kaminari-core (= 1.2.2)
kaminari-core (1.2.2) kaminari-core (1.2.2)
liner (0.2.4) liner (0.2.4)
listen (3.9.0) listen (3.10.0)
logger
rb-fsevent (~> 0.10, >= 0.10.3) rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10) rb-inotify (~> 0.9, >= 0.9.10)
logger (1.6.1) logger (1.7.0)
loofah (2.22.0) loofah (2.25.1)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.12.0) nokogiri (>= 1.12.0)
lumberjack (1.2.10) lumberjack (1.4.2)
mail (2.8.1) mail (2.9.0)
logger
mini_mime (>= 0.1.1) mini_mime (>= 0.1.1)
net-imap net-imap
net-pop net-pop
net-smtp net-smtp
marcel (1.0.4) marcel (1.1.0)
memoizable (0.4.2) memoizable (0.5.1)
thread_safe (~> 0.3, >= 0.3.1)
method_source (1.1.0) method_source (1.1.0)
mini_mime (1.1.5) mini_mime (1.1.5)
mini_portile2 (2.8.7) mini_portile2 (2.8.9)
minitest (5.25.1) minitest (6.0.4)
msgpack (1.7.2) drb (~> 2.0)
prism (~> 1.5)
msgpack (1.8.0)
nenv (0.3.0) nenv (0.3.0)
net-imap (0.4.16) net-imap (0.6.3)
date date
net-protocol net-protocol
net-pop (0.1.2) net-pop (0.1.2)
net-protocol net-protocol
net-protocol (0.2.2) net-protocol (0.2.2)
timeout timeout
net-smtp (0.5.0) net-smtp (0.5.1)
net-protocol net-protocol
nio4r (2.7.3) nio4r (2.7.5)
nokogiri (1.16.7) nokogiri (1.19.2)
mini_portile2 (~> 2.8.2) mini_portile2 (~> 2.8.2)
racc (~> 1.4) racc (~> 1.4)
notiffany (0.1.3) notiffany (0.1.3)
nenv (~> 0.1) nenv (~> 0.1)
shellany (~> 0.0) shellany (~> 0.0)
oj (3.16.6) oj (3.16.17)
bigdecimal (>= 3.0) bigdecimal (>= 3.0)
ostruct (>= 0.2) ostruct (>= 0.2)
ostruct (0.6.0) ostruct (0.6.3)
package_json (0.1.0) package_json (0.2.0)
parslet (2.0.0) parslet (2.0.0)
pg (1.5.8) pg (1.5.9)
pry (0.14.2) pp (0.6.3)
prettyprint
prettyprint (0.2.0)
prism (1.9.0)
pry (0.16.0)
coderay (~> 1.1) coderay (~> 1.1)
method_source (~> 1.0) method_source (~> 1.0)
psych (5.1.2) reline (>= 0.6.0)
psych (5.3.1)
date
stringio stringio
puma (6.4.3) puma (6.6.1)
nio4r (~> 2.0) nio4r (~> 2.0)
racc (1.8.1) racc (1.8.1)
rack (3.1.7) rack (3.2.6)
rack-proxy (0.7.7) rack-proxy (0.7.7)
rack rack
rack-session (2.0.0) rack-session (2.1.2)
base64 (>= 0.1.0)
rack (>= 3.0.0) rack (>= 3.0.0)
rack-test (2.1.0) rack-test (2.2.0)
rack (>= 1.3) rack (>= 1.3)
rackup (2.1.0) rackup (2.3.1)
rack (>= 3) rack (>= 3)
webrick (~> 1.8) rails (8.1.3)
rails (7.2.1) actioncable (= 8.1.3)
actioncable (= 7.2.1) actionmailbox (= 8.1.3)
actionmailbox (= 7.2.1) actionmailer (= 8.1.3)
actionmailer (= 7.2.1) actionpack (= 8.1.3)
actionpack (= 7.2.1) actiontext (= 8.1.3)
actiontext (= 7.2.1) actionview (= 8.1.3)
actionview (= 7.2.1) activejob (= 8.1.3)
activejob (= 7.2.1) activemodel (= 8.1.3)
activemodel (= 7.2.1) activerecord (= 8.1.3)
activerecord (= 7.2.1) activestorage (= 8.1.3)
activestorage (= 7.2.1) activesupport (= 8.1.3)
activesupport (= 7.2.1)
bundler (>= 1.15.0) bundler (>= 1.15.0)
railties (= 7.2.1) railties (= 8.1.3)
rails-controller-testing (1.0.5) rails-controller-testing (1.0.5)
actionpack (>= 5.0.1.rc1) actionpack (>= 5.0.1.rc1)
actionview (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1)
activesupport (>= 5.0.1.rc1) activesupport (>= 5.0.1.rc1)
rails-dom-testing (2.2.0) rails-dom-testing (2.3.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
minitest minitest
nokogiri (>= 1.6) nokogiri (>= 1.6)
rails-html-sanitizer (1.6.0) rails-html-sanitizer (1.7.0)
loofah (~> 2.21) loofah (~> 2.25)
nokogiri (~> 1.14) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
railties (7.2.1) railties (8.1.3)
actionpack (= 7.2.1) actionpack (= 8.1.3)
activesupport (= 7.2.1) activesupport (= 8.1.3)
irb (~> 1.13) irb (~> 1.13)
rackup (>= 1.0.0) rackup (>= 1.0.0)
rake (>= 12.2) rake (>= 12.2)
thor (~> 1.0, >= 1.2.2) thor (~> 1.0, >= 1.2.2)
tsort (>= 0.2)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
rake (13.2.1) rake (13.4.2)
rb-fsevent (0.11.2) rb-fsevent (0.11.2)
rb-inotify (0.11.1) rb-inotify (0.11.1)
ffi (~> 1.0) ffi (~> 1.0)
rdoc (6.7.0) rdoc (7.2.0)
erb
psych (>= 4.0.0) psych (>= 4.0.0)
redcarpet (3.6.0) tsort
reline (0.5.10) redcarpet (3.6.1)
reline (0.6.3)
io-console (~> 0.5) io-console (~> 0.5)
rspec (3.13.0) rspec (3.13.2)
rspec-core (~> 3.13.0) rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0) rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0) rspec-mocks (~> 3.13.0)
rspec-core (3.13.1) rspec-core (3.13.6)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-expectations (3.13.3) rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-mocks (3.13.1) rspec-mocks (3.13.8)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-rails (7.0.1) rspec-rails (7.0.2)
actionpack (>= 7.0) actionpack (>= 7.0)
activesupport (>= 7.0) activesupport (>= 7.0)
railties (>= 7.0) railties (>= 7.0)
@ -260,9 +281,9 @@ GEM
rspec-expectations (~> 3.13) rspec-expectations (~> 3.13)
rspec-mocks (~> 3.13) rspec-mocks (~> 3.13)
rspec-support (~> 3.13) rspec-support (~> 3.13)
rspec-support (3.13.1) rspec-support (3.13.7)
securerandom (0.3.1) securerandom (0.4.1)
semantic_range (3.0.0) semantic_range (3.1.1)
shakapacker (8.0.2) shakapacker (8.0.2)
activesupport (>= 5.2) activesupport (>= 5.2)
package_json package_json
@ -271,27 +292,28 @@ GEM
semantic_range (>= 2.3.0) semantic_range (>= 2.3.0)
shellany (0.0.1) shellany (0.0.1)
signed_multiset (0.2.1) signed_multiset (0.2.1)
sqlite3 (2.1.0) sqlite3 (2.1.1)
mini_portile2 (~> 2.8.0) mini_portile2 (~> 2.8.0)
stringio (3.1.1) stringio (3.2.0)
thor (1.3.2) thor (1.5.0)
thread_safe (0.3.6) timeout (0.6.1)
timeout (0.4.1) tsort (0.2.0)
tzinfo (2.0.6) tzinfo (2.0.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
tzinfo-data (1.2024.2) tzinfo-data (1.2026.1)
tzinfo (>= 1.0.0) tzinfo (>= 1.0.0)
unitwise (2.3.0) unitwise (2.3.0)
liner (~> 0.2) liner (~> 0.2)
memoizable (~> 0.4) memoizable (~> 0.4)
parslet (~> 2.0) parslet (~> 2.0)
signed_multiset (~> 0.2) signed_multiset (~> 0.2)
useragent (0.16.10) uri (1.1.1)
webrick (1.8.2) useragent (0.16.11)
websocket-driver (0.7.6) websocket-driver (0.8.0)
base64
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5) websocket-extensions (0.1.5)
zeitwerk (2.6.18) zeitwerk (2.7.5)
PLATFORMS PLATFORMS
ruby ruby
@ -309,7 +331,7 @@ DEPENDENCIES
oj (~> 3.16.6) oj (~> 3.16.6)
pg (~> 1.5.8) pg (~> 1.5.8)
puma (~> 6.4) puma (~> 6.4)
rails (= 7.2.1) rails (= 8.1.3)
rails-controller-testing rails-controller-testing
redcarpet (~> 3.6.0) redcarpet (~> 3.6.0)
rspec-rails (~> 7.0.1) rspec-rails (~> 7.0.1)
@ -319,4 +341,4 @@ DEPENDENCIES
unitwise (~> 2.3.0) unitwise (~> 2.3.0)
BUNDLED WITH BUNDLED WITH
2.5.20 4.0.10

View File

@ -42,7 +42,7 @@ class TaskItemsController < ApplicationController
new_status = !params[:invert].present? new_status = !params[:invert].present?
TaskItem.transaction do TaskItem.transaction do
@task_items = @task_list.task_items.find(ids) @task_items = @task_list.task_items.find(ids)
@task_items.each { |i| i.update_attribute(:completed, new_status) } @task_items.each { |i| i.update_column(:completed, new_status) }
end end
TaskChannel.update_task_list(@task_list) TaskChannel.update_task_list(@task_list)

View File

@ -8,32 +8,27 @@
<script setup> <script setup>
import { ref } from "vue"; import { ref, watch } from "vue";
import debounce from "lodash/debounce"; import debounce from "lodash/debounce";
const emit = defineEmits(["update:modelValue"]);
const props = defineProps({ const props = defineProps({
placeholder: { placeholder: {
required: false, required: false,
type: String, type: String,
default: "" default: ""
},
modelValue: {
required: false,
type: String,
default: ""
} }
}); });
const text = ref(null); const model = defineModel({ type: String, default: null });
const text = ref(model.value);
watch(model, (val) => { text.value = val; });
const triggerInput = debounce(function() { const triggerInput = debounce(function() {
emit("update:modelValue", text.value); model.value = text.value;
}, },
250, 250,
{ leading: false, trailing: true }) { leading: false, trailing: true });
function userUpdateText(newText) { function userUpdateText(newText) {
if (text.value !== newText) { if (text.value !== newText) {
@ -42,10 +37,4 @@ function userUpdateText(newText) {
} }
} }
function propUpdateText(newText) {
if (text.value === null && text.value !== newText) {
text.value = newText;
}
}
</script> </script>

View File

@ -87,10 +87,10 @@
return api.getSearchIngredients(text); return api.getSearchIngredients(text);
} }
function searchItemSelected(ingredient) { function searchItemSelected(selectedIngredient) {
ingredient.value = ingredient || null; ingredient.value = selectedIngredient || null;
ingredient_name.value = ingredient.name || null; ingredient_name.value = selectedIngredient.name || null;
density.value = ingredient.density || null; density.value = selectedIngredient.density || null;
} }
function getErrors(type) { function getErrors(type) {

View File

@ -25,10 +25,10 @@
</tr> </tr>
<tr> <tr>
<td> <td>
<app-search-text placeholder="search names" :value="search.name" @update:modelValue="setSearchName($event)"></app-search-text> <app-search-text placeholder="search names" :model-value="search.name" @update:modelValue="setSearchName($event)"></app-search-text>
</td> </td>
<td> <td>
<app-search-text placeholder="search tags" :value="search.tags" @update:modelValue="setSearchTags($event)"></app-search-text> <app-search-text placeholder="search tags" :model-value="search.tags" @update:modelValue="setSearchTags($event)"></app-search-text>
</td> </td>
<td colspan="5"></td> <td colspan="5"></td>
</tr> </tr>

View File

@ -9,7 +9,7 @@ class User < ApplicationRecord
validates :username, presence: true, uniqueness: { case_sensitive: false } validates :username, presence: true, uniqueness: { case_sensitive: false }
def self.authenticate(username, password) def self.authenticate(username, password)
find_by_username(username).try(:authenticate, password) find_by(username: username)&.authenticate(password)
end end
def display_name def display_name

View File

@ -24,7 +24,7 @@ require_relative '../lib/unit_conversion'
module Parsley module Parsley
class Application < Rails::Application class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version. # Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.2 config.load_defaults 8.0
config.autoload_lib(ignore: %w(assets tasks unit_conversion unit_conversion.rb)) config.autoload_lib(ignore: %w(assets tasks unit_conversion unit_conversion.rb))

View File

@ -1,10 +1,8 @@
Rails.application.configure do Rails.application.configure do
# Verifies that versions and hashed value of the package contents in the project's package.json
config.webpacker.check_yarn_integrity = false
# Settings specified here will take precedence over those in config/application.rb. # Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests. # Code is not reloaded between requests.
config.cache_classes = true config.enable_reloading = false
# Eager load code on boot. This eager loads most of Rails and # Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers # your application in memory, allowing both threaded web servers
@ -68,8 +66,8 @@ Rails.application.configure do
# the I18n.default_locale when a translation cannot be found). # the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true config.i18n.fallbacks = true
# Send deprecation notices to registered listeners. # Don't log any deprecations.
config.active_support.deprecation = :notify config.active_support.report_deprecations = false
# Use default logging formatter so that PID and timestamp are not suppressed. # Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new config.log_formatter = ::Logger::Formatter.new

View File

@ -2,7 +2,7 @@ Rails.application.configure do
# Settings specified here will take precedence over those in config/application.rb. # Settings specified here will take precedence over those in config/application.rb.
# Code is not reloaded between requests. # Code is not reloaded between requests.
config.cache_classes = true config.enable_reloading = false
# Eager load code on boot. This eager loads most of Rails and # Eager load code on boot. This eager loads most of Rails and
# your application in memory, allowing both threaded web servers # your application in memory, allowing both threaded web servers
@ -56,8 +56,8 @@ Rails.application.configure do
# the I18n.default_locale when a translation cannot be found). # the I18n.default_locale when a translation cannot be found).
config.i18n.fallbacks = true config.i18n.fallbacks = true
# Send deprecation notices to registered listeners. # Don't log any deprecations.
config.active_support.deprecation = :notify config.active_support.report_deprecations = false
# Use default logging formatter so that PID and timestamp are not suppressed. # Use default logging formatter so that PID and timestamp are not suppressed.
config.log_formatter = ::Logger::Formatter.new config.log_formatter = ::Logger::Formatter.new

View File

@ -10,107 +10,107 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.2].define(version: 2018_09_15_134841) do ActiveRecord::Schema[8.1].define(version: 2018_09_15_134841) do
create_table "food_units", force: :cascade do |t| create_table "food_units", force: :cascade do |t|
t.integer "food_id", null: false t.integer "food_id", null: false
t.string "name", null: false
t.decimal "gram_weight", precision: 10, scale: 2, null: false t.decimal "gram_weight", precision: 10, scale: 2, null: false
t.string "name", null: false
t.index ["food_id"], name: "index_food_units_on_food_id" t.index ["food_id"], name: "index_food_units_on_food_id"
end end
create_table "foods", force: :cascade do |t| create_table "foods", force: :cascade do |t|
t.string "name"
t.string "density"
t.text "notes"
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.string "ndbn", limit: 25
t.decimal "water", precision: 10, scale: 2
t.decimal "protein", precision: 10, scale: 2
t.decimal "lipids", precision: 10, scale: 2
t.decimal "ash", precision: 10, scale: 2 t.decimal "ash", precision: 10, scale: 2
t.decimal "carbohydrates", precision: 10, scale: 2
t.integer "kcal"
t.decimal "fiber", precision: 10, scale: 1
t.decimal "sugar", precision: 10, scale: 2
t.integer "user_id"
t.integer "calcium" t.integer "calcium"
t.decimal "carbohydrates", precision: 10, scale: 2
t.decimal "cholesterol", precision: 10, scale: 3
t.decimal "copper", precision: 10, scale: 3
t.datetime "created_at", precision: nil, null: false
t.string "density"
t.decimal "fiber", precision: 10, scale: 1
t.decimal "iron", precision: 10, scale: 2 t.decimal "iron", precision: 10, scale: 2
t.integer "kcal"
t.decimal "lipids", precision: 10, scale: 2
t.integer "magnesium" t.integer "magnesium"
t.decimal "manganese", precision: 10, scale: 3
t.string "name"
t.string "ndbn", limit: 25
t.text "notes"
t.integer "phosphorus" t.integer "phosphorus"
t.integer "potassium" t.integer "potassium"
t.decimal "protein", precision: 10, scale: 2
t.integer "sodium" t.integer "sodium"
t.decimal "zinc", precision: 10, scale: 2 t.decimal "sugar", precision: 10, scale: 2
t.decimal "copper", precision: 10, scale: 3 t.datetime "updated_at", precision: nil, null: false
t.decimal "manganese", precision: 10, scale: 3 t.integer "user_id"
t.decimal "vit_c", precision: 10, scale: 1
t.decimal "vit_b6", precision: 10, scale: 3
t.decimal "vit_b12", precision: 10, scale: 2
t.integer "vit_a" t.integer "vit_a"
t.decimal "vit_e", precision: 10, scale: 2 t.decimal "vit_b12", precision: 10, scale: 2
t.decimal "vit_b6", precision: 10, scale: 3
t.decimal "vit_c", precision: 10, scale: 1
t.decimal "vit_d", precision: 10, scale: 1 t.decimal "vit_d", precision: 10, scale: 1
t.decimal "vit_e", precision: 10, scale: 2
t.decimal "vit_k", precision: 10, scale: 1 t.decimal "vit_k", precision: 10, scale: 1
t.decimal "cholesterol", precision: 10, scale: 3 t.decimal "water", precision: 10, scale: 2
t.decimal "zinc", precision: 10, scale: 2
t.index ["ndbn"], name: "index_foods_on_ndbn" t.index ["ndbn"], name: "index_foods_on_ndbn"
end end
create_table "logs", force: :cascade do |t| create_table "logs", force: :cascade do |t|
t.integer "user_id" t.datetime "created_at", precision: nil, null: false
t.datetime "date", precision: nil
t.text "notes"
t.integer "rating"
t.integer "recipe_id" t.integer "recipe_id"
t.integer "source_recipe_id" t.integer "source_recipe_id"
t.datetime "date", precision: nil
t.integer "rating"
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false
t.text "notes" t.integer "user_id"
end end
create_table "notes", force: :cascade do |t| create_table "notes", force: :cascade do |t|
t.integer "user_id", null: false
t.text "content", null: false t.text "content", null: false
t.datetime "created_at", precision: nil, null: false t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false
t.integer "user_id", null: false
t.index ["user_id"], name: "index_notes_on_user_id" t.index ["user_id"], name: "index_notes_on_user_id"
end end
create_table "recipe_ingredients", force: :cascade do |t| create_table "recipe_ingredients", force: :cascade do |t|
t.integer "food_id"
t.integer "recipe_id"
t.string "name"
t.integer "sort_order"
t.string "quantity"
t.string "units"
t.datetime "created_at", precision: nil, null: false t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false t.integer "food_id"
t.string "name"
t.text "preparation" t.text "preparation"
t.string "quantity"
t.integer "recipe_as_ingredient_id" t.integer "recipe_as_ingredient_id"
t.integer "recipe_id"
t.integer "sort_order"
t.string "units"
t.datetime "updated_at", precision: nil, null: false
t.index ["recipe_id"], name: "index_recipe_ingredients_on_recipe_id" t.index ["recipe_id"], name: "index_recipe_ingredients_on_recipe_id"
end end
create_table "recipe_steps", force: :cascade do |t| create_table "recipe_steps", force: :cascade do |t|
t.datetime "created_at", precision: nil, null: false
t.integer "recipe_id" t.integer "recipe_id"
t.integer "sort_order" t.integer "sort_order"
t.text "step" t.text "step"
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false
t.index ["recipe_id"], name: "index_recipe_steps_on_recipe_id" t.index ["recipe_id"], name: "index_recipe_steps_on_recipe_id"
end end
create_table "recipes", force: :cascade do |t| create_table "recipes", force: :cascade do |t|
t.string "name"
t.text "description"
t.text "source"
t.string "yields"
t.integer "total_time"
t.integer "active_time" t.integer "active_time"
t.datetime "created_at", precision: nil, null: false t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
t.boolean "deleted" t.boolean "deleted"
t.integer "user_id" t.text "description"
t.boolean "is_log"
t.float "rating"
t.text "step_text"
t.boolean "is_ingredient" t.boolean "is_ingredient"
t.boolean "is_log"
t.string "name"
t.float "rating"
t.text "source"
t.text "step_text"
t.integer "total_time"
t.datetime "updated_at", precision: nil, null: false
t.integer "user_id"
t.string "yields"
end end
create_table "recipes_tags", id: false, force: :cascade do |t| create_table "recipes_tags", id: false, force: :cascade do |t|
@ -121,94 +121,94 @@ ActiveRecord::Schema[7.2].define(version: 2018_09_15_134841) do
end end
create_table "tags", force: :cascade do |t| create_table "tags", force: :cascade do |t|
t.string "name"
t.string "lowercase_name"
t.datetime "created_at", precision: nil, null: false t.datetime "created_at", precision: nil, null: false
t.string "lowercase_name"
t.string "name"
t.datetime "updated_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false
t.index ["lowercase_name"], name: "index_tags_on_lowercase_name", unique: true t.index ["lowercase_name"], name: "index_tags_on_lowercase_name", unique: true
end end
create_table "task_items", force: :cascade do |t| create_table "task_items", force: :cascade do |t|
t.integer "task_list_id", null: false t.boolean "completed"
t.datetime "created_at", precision: nil, null: false
t.string "name" t.string "name"
t.string "quantity" t.string "quantity"
t.datetime "created_at", precision: nil, null: false t.integer "task_list_id", null: false
t.datetime "updated_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false
t.boolean "completed"
t.index ["task_list_id"], name: "index_task_items_on_task_list_id" t.index ["task_list_id"], name: "index_task_items_on_task_list_id"
end end
create_table "task_lists", force: :cascade do |t| create_table "task_lists", force: :cascade do |t|
t.integer "user_id", null: false
t.string "name"
t.datetime "created_at", precision: nil, null: false t.datetime "created_at", precision: nil, null: false
t.string "name"
t.datetime "updated_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false
t.integer "user_id", null: false
t.index ["user_id"], name: "index_task_lists_on_user_id" t.index ["user_id"], name: "index_task_lists_on_user_id"
end end
create_table "usda_food_weights", force: :cascade do |t| create_table "usda_food_weights", force: :cascade do |t|
t.integer "usda_food_id", null: false
t.decimal "amount", precision: 7, scale: 3 t.decimal "amount", precision: 7, scale: 3
t.datetime "created_at", precision: nil, null: false
t.string "description" t.string "description"
t.decimal "gram_weight", precision: 7, scale: 1 t.decimal "gram_weight", precision: 7, scale: 1
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false
t.integer "usda_food_id", null: false
t.index ["usda_food_id"], name: "index_usda_food_weights_on_usda_food_id" t.index ["usda_food_id"], name: "index_usda_food_weights_on_usda_food_id"
end end
create_table "usda_foods", force: :cascade do |t| create_table "usda_foods", force: :cascade do |t|
t.string "ndbn", limit: 25
t.string "long_description"
t.string "short_description"
t.decimal "water", precision: 10, scale: 2
t.integer "kcal"
t.decimal "protein", precision: 10, scale: 2
t.decimal "lipid", precision: 10, scale: 2
t.decimal "ash", precision: 10, scale: 2 t.decimal "ash", precision: 10, scale: 2
t.integer "calcium"
t.decimal "carbohydrates", precision: 10, scale: 2 t.decimal "carbohydrates", precision: 10, scale: 2
t.decimal "cholesterol", precision: 10, scale: 3
t.decimal "copper", precision: 10, scale: 3
t.datetime "created_at", precision: nil, null: false
t.decimal "fiber", precision: 10, scale: 1 t.decimal "fiber", precision: 10, scale: 1
t.decimal "sugar", precision: 10, scale: 2
t.decimal "gram_weight_1", precision: 9, scale: 2 t.decimal "gram_weight_1", precision: 9, scale: 2
t.decimal "gram_weight_2", precision: 9, scale: 2 t.decimal "gram_weight_2", precision: 9, scale: 2
t.string "gram_weight_desc_1" t.string "gram_weight_desc_1"
t.string "gram_weight_desc_2" t.string "gram_weight_desc_2"
t.text "ingredients"
t.decimal "iron", precision: 10, scale: 2
t.integer "kcal"
t.decimal "lipid", precision: 10, scale: 2
t.string "long_description"
t.integer "magnesium"
t.decimal "manganese", precision: 10, scale: 3
t.string "manufacturer"
t.string "ndbn", limit: 25
t.string "nutrient_unit"
t.integer "phosphorus"
t.integer "potassium"
t.decimal "protein", precision: 10, scale: 2
t.string "refuse_description" t.string "refuse_description"
t.integer "refuse_percent" t.integer "refuse_percent"
t.string "scientific_name" t.string "scientific_name"
t.datetime "created_at", precision: nil, null: false t.string "short_description"
t.datetime "updated_at", precision: nil, null: false
t.integer "calcium"
t.decimal "iron", precision: 10, scale: 2
t.integer "magnesium"
t.integer "phosphorus"
t.integer "potassium"
t.integer "sodium" t.integer "sodium"
t.decimal "zinc", precision: 10, scale: 2
t.decimal "copper", precision: 10, scale: 3
t.decimal "manganese", precision: 10, scale: 3
t.decimal "vit_c", precision: 10, scale: 1
t.decimal "vit_b6", precision: 10, scale: 3
t.decimal "vit_b12", precision: 10, scale: 2
t.integer "vit_a"
t.decimal "vit_e", precision: 10, scale: 2
t.decimal "vit_d", precision: 10, scale: 1
t.decimal "vit_k", precision: 10, scale: 1
t.decimal "cholesterol", precision: 10, scale: 3
t.string "source" t.string "source"
t.string "manufacturer" t.decimal "sugar", precision: 10, scale: 2
t.text "ingredients" t.datetime "updated_at", precision: nil, null: false
t.string "nutrient_unit" t.integer "vit_a"
t.decimal "vit_b12", precision: 10, scale: 2
t.decimal "vit_b6", precision: 10, scale: 3
t.decimal "vit_c", precision: 10, scale: 1
t.decimal "vit_d", precision: 10, scale: 1
t.decimal "vit_e", precision: 10, scale: 2
t.decimal "vit_k", precision: 10, scale: 1
t.decimal "water", precision: 10, scale: 2
t.decimal "zinc", precision: 10, scale: 2
t.index ["long_description"], name: "index_usda_foods_on_long_description" t.index ["long_description"], name: "index_usda_foods_on_long_description"
t.index ["ndbn"], name: "index_usda_foods_on_ndbn" t.index ["ndbn"], name: "index_usda_foods_on_ndbn"
end end
create_table "users", force: :cascade do |t| create_table "users", force: :cascade do |t|
t.string "username" t.boolean "admin"
t.datetime "created_at", precision: nil, null: false
t.string "email" t.string "email"
t.string "full_name" t.string "full_name"
t.string "password_digest" t.string "password_digest"
t.boolean "admin"
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false
t.string "username"
end end
end end