Compare commits

...

7 commits

Author SHA1 Message Date
Mohammad Kanaan
54bdd52e75 feat: add user auth and bcrypt gem with related schema updates
Some checks failed
CI / scan_ruby (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
2026-05-31 00:27:35 +03:00
Mohammad Kanaan
5c4667ed02 fix: add voting functionality with votable concern and updated price report and vote models. 2026-05-30 23:51:16 +03:00
Mohammad Kanaan
da586ae3d3 feat: add votable concern 2026-05-30 23:23:19 +03:00
Mohammad Kanaan
82f48c9ad3 WIP 2 2026-05-30 19:39:28 +03:00
Mohammad Kanaan
5a9f9ee10c WIP 1 2026-05-30 19:15:24 +03:00
Mohammad Kanaan
362ed3596b merge adming and guest into users 2026-05-30 17:54:26 +03:00
Mohammad Kanaan
6b9d9dee8a feat: add dependent associations for moderation logs and price reports 2026-05-26 20:37:52 +03:00
40 changed files with 581 additions and 213 deletions

10
.idea/.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Ignored default folder with query files
/queries/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

8
.idea/modules.xml Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/price-point-api.iml" filepath="$PROJECT_DIR$/.idea/price-point-api.iml" />
</modules>
</component>
</project>

252
.idea/price-point-api.iml Normal file
View file

@ -0,0 +1,252 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="RUBY_MODULE" version="4">
<component name="FacetManager">
<facet type="RailsFacetType" name="Ruby on Rails">
<configuration>
<RAILS_FACET_CONFIG_ID NAME="RAILS_FACET_SUPPORT_REMOVED" VALUE="false" />
<RAILS_FACET_CONFIG_ID NAME="RAILS_TESTS_SOURCES_PATCHED" VALUE="true" />
<RAILS_FACET_CONFIG_ID NAME="RAILS_FACET_APPLICATION_ROOT" VALUE="$MODULE_DIR$" />
</configuration>
</facet>
</component>
<component name="ModuleRunConfigurationManager">
<shared />
</component>
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/features" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/spec" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/test" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/.bundle" />
<excludeFolder url="file://$MODULE_DIR$/components" />
<excludeFolder url="file://$MODULE_DIR$/log" />
<excludeFolder url="file://$MODULE_DIR$/public/packs" />
<excludeFolder url="file://$MODULE_DIR$/public/system" />
<excludeFolder url="file://$MODULE_DIR$/tmp" />
<excludeFolder url="file://$MODULE_DIR$/vendor/bundle" />
<excludeFolder url="file://$MODULE_DIR$/vendor/cache" />
</content>
<orderEntry type="jdk" jdkName="RVM: ruby-3.4.4" jdkType="RUBY_SDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" scope="PROVIDED" name="actioncable (v8.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="actionmailbox (v8.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="actionmailer (v8.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="actionpack (v8.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="actiontext (v8.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="actionview (v8.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="activejob (v8.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="activemodel (v8.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="activerecord (v8.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="activestorage (v8.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="activesupport (v8.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="TEST" name="annotaterb (v4.22.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="ast (v2.4.3, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="base64 (v0.3.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="bcrypt (v3.1.21, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="bcrypt_pbkdf (v1.1.2, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="benchmark (v0.5.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="bigdecimal (v4.1.2, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="bootsnap (v1.24.4, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="TEST" name="brakeman (v8.0.4, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="builder (v3.3.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="bundler (v2.7.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="choice (v0.2.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="concurrent-ruby (v1.3.6, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="connection_pool (v3.0.2, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="crass (v1.0.6, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="date (v3.5.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="debug (v1.11.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="dotenv (v3.2.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="TEST" name="dotenv-rails (v3.2.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="drb (v2.2.3, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="ed25519 (v1.4.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="erb (v6.0.4, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="erubi (v1.13.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="et-orbi (v1.4.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="fugit (v1.12.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="globalid (v1.3.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="i18n (v1.14.8, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="io-console (v0.8.2, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="irb (v1.18.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="json (v2.19.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="kamal (v2.11.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="language_server-protocol (v3.17.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="lint_roller (v1.1.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="logger (v1.7.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="loofah (v2.25.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="mail (v2.9.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="marcel (v1.1.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="mini_mime (v1.1.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="minitest (v6.0.6, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="msgpack (v1.8.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="net-imap (v0.6.4, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="net-pop (v0.1.2, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="net-protocol (v0.2.2, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="net-scp (v4.1.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="net-sftp (v4.0.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="net-smtp (v0.5.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="net-ssh (v7.3.2, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="nio4r (v2.7.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="nokogiri (v1.19.3, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="ostruct (v0.6.3, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="parallel (v2.1.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="parser (v3.3.11.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="pg (v1.6.3, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="pp (v0.6.3, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="prettyprint (v0.2.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="prism (v1.9.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="psych (v5.3.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="puma (v8.0.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="raabro (v1.4.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="racc (v1.8.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rack (v3.2.6, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rack-session (v2.1.2, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rack-test (v2.2.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rackup (v2.3.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rails (v8.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rails-dom-testing (v2.3.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="TEST" name="rails-erd (v1.7.2, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rails-html-sanitizer (v1.7.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="railties (v8.0.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rainbow (v3.1.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rake (v13.4.2, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rdoc (v7.2.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="regexp_parser (v2.12.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="reline (v0.6.3, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rexml (v3.4.4, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rubocop (v1.86.2, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rubocop-ast (v1.49.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rubocop-performance (v1.26.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="rubocop-rails (v2.35.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="TEST" name="rubocop-rails-omakase (v1.1.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="ruby-graphviz (v1.2.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="ruby-progressbar (v1.13.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="securerandom (v0.4.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="solid_cable (v3.0.12, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="solid_cache (v1.0.10, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="solid_queue (v1.4.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="sshkit (v1.25.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="stringio (v3.2.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="thor (v1.5.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="thruster (v0.1.20, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="timeout (v0.6.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="tsort (v0.2.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="tzinfo (v2.0.6, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="unicode-display_width (v3.2.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="unicode-emoji (v4.2.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="uri (v1.1.1, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="useragent (v0.16.11, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="websocket-driver (v0.8.0, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="websocket-extensions (v0.1.5, RVM: ruby-3.4.4) [gem]" level="application" />
<orderEntry type="library" scope="PROVIDED" name="zeitwerk (v2.7.5, RVM: ruby-3.4.4) [gem]" level="application" />
</component>
<component name="RModuleSettingsStorage">
<LOAD_PATH number="0" />
<I18N_FOLDERS number="1" string0="$MODULE_DIR$/config/locales" />
</component>
<component name="RailsPaths" isManagedAutomatically="true">
<entry key="app">
<value>file://$MODULE_DIR$/app</value>
</entry>
<entry key="app/assets">
<value>file://$MODULE_DIR$/app/assets</value>
</entry>
<entry key="app/channels">
<value>file://$MODULE_DIR$/app/channels</value>
</entry>
<entry key="app/controllers">
<value>file://$MODULE_DIR$/app/controllers</value>
</entry>
<entry key="app/helpers">
<value>file://$MODULE_DIR$/app/helpers</value>
</entry>
<entry key="app/mailers">
<value>file://$MODULE_DIR$/app/mailers</value>
</entry>
<entry key="app/models">
<value>file://$MODULE_DIR$/app/models</value>
</entry>
<entry key="app/views">
<value>file://$MODULE_DIR$/app/views</value>
</entry>
<entry key="config">
<value>file://$MODULE_DIR$/config</value>
</entry>
<entry key="config/cable">
<value>file://$MODULE_DIR$/config/cable.yml</value>
</entry>
<entry key="config/cache">
<value>file://$MODULE_DIR$/config/cache.yml</value>
</entry>
<entry key="config/database">
<value>file://$MODULE_DIR$/config/database.yml</value>
</entry>
<entry key="config/environment">
<value>file://$MODULE_DIR$/config/environment.rb</value>
</entry>
<entry key="config/environments">
<value>file://$MODULE_DIR$/config/environments</value>
</entry>
<entry key="config/initializers">
<value>file://$MODULE_DIR$/config/initializers</value>
</entry>
<entry key="config/locales">
<value>file://$MODULE_DIR$/config/locales</value>
</entry>
<entry key="config/routes">
<value>file://$MODULE_DIR$/config/routes</value>
</entry>
<entry key="config/routes.rb">
<value>file://$MODULE_DIR$/config/routes.rb</value>
</entry>
<entry key="config/solid_cache">
<value>file://$MODULE_DIR$/config/solid_cache.yml</value>
</entry>
<entry key="db">
<value>file://$MODULE_DIR$/db</value>
</entry>
<entry key="db/migrate">
<value>file://$MODULE_DIR$/db/migrate</value>
</entry>
<entry key="db/seeds.rb">
<value>file://$MODULE_DIR$/db/seeds.rb</value>
</entry>
<entry key="lib">
<value>file://$MODULE_DIR$/lib</value>
</entry>
<entry key="lib/assets">
<value>file://$MODULE_DIR$/lib/assets</value>
</entry>
<entry key="lib/tasks">
<value>file://$MODULE_DIR$/lib/tasks</value>
</entry>
<entry key="lib/templates">
<value>file://$MODULE_DIR$/lib/templates</value>
</entry>
<entry key="log">
<value>file://$MODULE_DIR$/log/development.log</value>
</entry>
<entry key="public">
<value>file://$MODULE_DIR$/public</value>
</entry>
<entry key="public/javascripts">
<value>file://$MODULE_DIR$/public/javascripts</value>
</entry>
<entry key="public/stylesheets">
<value>file://$MODULE_DIR$/public/stylesheets</value>
</entry>
<entry key="test/mailers/previews">
<value>file://$MODULE_DIR$/test/mailers/previews</value>
<value>file://$MODULE_DIR$/test/mailers/previews</value>
</entry>
<entry key="tmp">
<value>file://$MODULE_DIR$/tmp</value>
</entry>
<entry key="vendor">
<value>file://$MODULE_DIR$/vendor</value>
</entry>
<entry key="vendor/assets">
<value>file://$MODULE_DIR$/vendor/assets</value>
</entry>
</component>
</module>

6
.idea/vcs.xml Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

View file

@ -0,0 +1,8 @@
ts=2026-05-30T17:25:04.225Z type=context scope=developer-profile content="Developer Profile - Abdo Achkar: TS dev 2yr, mostly React frontend. Backend: Next.js server actions, basic Laravel ecommerce (admin middleware, no policies). Light Java/C++, solid OOP but functional instincts. Ruby beginner-intermediate (built mini-spec DSL with blocks/Procs/modules). Rails early (understands AR, polymorphic, nested routes, no auth yet). Project: price-point-api Rails 8 API-only crowdsourced price reporting. Learning goal: deep Rails understanding through building features. Growth areas: 1) Ruby idioms 2) Rails conventions 3) AR depth 4) testing 5) auth." tags=profile,developer,ruby,rails
ts=2026-05-30T17:25:27.520Z type=learning scope=developer-profile content="mini-spec project at /Users/abdoachkar/programming/personal/ruby/mini-spec reveals coding style: functional instincts (Proc as matcher instead of matcher object), hashes over objects for known shapes, explicit self on methods unnecessarily, parentheses on if conditions. Good: blocks, yield, module DSL design, rescue handling, method chaining. These are the Ruby idioms to correct as we go." tags=ruby,style,gaps
ts=2026-05-30T17:25:32.838Z type=context scope=price-point-api content="price-point-api: Rails 8 API-only, Ruby 3.4.4. Models: User, Chain (has_many stores), Store (belongs_to chain, has_many price_reports), Product (has_many price_reports), PriceReport (belongs_to product/store/user, polymorphic moderation_logs/votes), Vote (polymorphic votable), ModerationLog (polymorphic moderatable). Active Storage on Chain/Store/Product. No auth wired up (password_digest exists, no has_secure_password). No service objects, concerns, serializers, or background jobs. Scaffold-style controllers and tests." tags=architecture,rails,models
ts=2026-05-30T17:25:34.868Z type=preference scope=developer-profile content="Teaching approach: guide through building features on price-point-api, not isolated drills. Socratic method — hints and questions before solutions. Correct Ruby idioms as they arise naturally. Priority: auth first (unblocks everything, hits multiple growth areas)." tags=teaching,approach
ts=2026-05-30T20:44:39.127Z type=decision scope=price-point-api content="price-point-api: Added Votable concern (app/models/concerns/votable.rb). PriceReport includes Votable. Methods: upvote!(user), downvote!(user) with toggle logic (same direction = destroy vote, opposite direction = switch), upvote_count/downvote_count via query (votes.where query). Rejected counter cache — directional counts (upvotes/downvotes) make Rails' built-in counter_cache unsuitable. Stale upvotes_count/downvotes_count columns need migration to drop." tags=voting,concerns,architecture
ts=2026-05-30T20:44:41.808Z type=learning scope=developer-profile content="Learned: ActiveSupport::Concern syntax (extend + included do), find_by(user:) shorthand, ! vs no-! consistency in method calls, counter_cache limitations with polymorphic + directional counts, parentheses optional in Ruby when no args. Built Votable concern from scratch with toggle logic." tags=ruby,rails,concerns,counter-cache
ts=2026-05-30T20:45:19.960Z type=preference scope=developer-profile content="Teaching style correction: Don't recommend patterns without first fully analyzing fit. Counter cache example — recommended before realizing directional counts break it. Verify the pattern actually solves the user's concrete problem before suggesting it. If unsure, say so and let the user decide." tags=teaching,style,lessons
ts=2026-05-30T21:26:45.561Z type=preference scope=developer-profile content="Auth style preferences: prefers `unless` over guard-clause-with-return for before_action authentication. Doesn't care about strict \"Bearer\" prefix validation in token extraction — fine with split.last."

View file

@ -10,7 +10,7 @@ gem "puma", ">= 5.0"
# gem "jbuilder" # gem "jbuilder"
# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] # Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
# gem "bcrypt", "~> 3.1.7" gem "bcrypt", "~> 3.1.7"
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem "tzinfo-data", platforms: %i[ windows jruby ] gem "tzinfo-data", platforms: %i[ windows jruby ]

View file

@ -77,6 +77,7 @@ GEM
activesupport (>= 6.0.0) activesupport (>= 6.0.0)
ast (2.4.3) ast (2.4.3)
base64 (0.3.0) base64 (0.3.0)
bcrypt (3.1.21)
bcrypt_pbkdf (1.1.2) bcrypt_pbkdf (1.1.2)
benchmark (0.5.0) benchmark (0.5.0)
bigdecimal (4.1.2) bigdecimal (4.1.2)
@ -339,6 +340,7 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
annotaterb annotaterb
bcrypt (~> 3.1.7)
bootsnap bootsnap
brakeman brakeman
debug debug

View file

@ -1,2 +1,15 @@
class ApplicationController < ActionController::API class ApplicationController < ActionController::API
before_action :authenticate!
private
def authenticate!
token = request.headers["Authorization"]&.split(" ")&.last
@current_user = User.find_by(token:)
render json: { error: "Unauthorized" }, status: :unauthorized unless @current_user
end
def current_user
@current_user
end
end end

View file

@ -1,51 +0,0 @@
class GuestsController < ApplicationController
before_action :set_guest, only: %i[ show update destroy ]
# GET /guests
def index
@guests = Guest.all
render json: @guests
end
# GET /guests/1
def show
render json: @guest
end
# POST /guests
def create
@guest = Guest.new(guest_params)
if @guest.save
render json: @guest, status: :created, location: @guest
else
render json: @guest.errors, status: :unprocessable_content
end
end
# PATCH/PUT /guests/1
def update
if @guest.update(guest_params)
render json: @guest
else
render json: @guest.errors, status: :unprocessable_content
end
end
# DELETE /guests/1
def destroy
@guest.destroy!
end
private
# Use callbacks to share common setup or constraints between actions.
def set_guest
@guest = Guest.find(params.expect(:id))
end
# Only allow a list of trusted parameters through.
def guest_params
params.expect(guest: [ :username, :name ])
end
end

View file

@ -3,7 +3,8 @@ class PriceReportsController < ApplicationController
# GET /price_reports # GET /price_reports
def index def index
@price_reports = PriceReport.all @product = Product.find(params[:product_id])
@price_reports = @product.price_reports
render json: @price_reports render json: @price_reports
end end
@ -33,6 +34,10 @@ class PriceReportsController < ApplicationController
end end
end end
def upvote
end
# DELETE /price_reports/1 # DELETE /price_reports/1
def destroy def destroy
@price_report.destroy! @price_report.destroy!
@ -46,6 +51,6 @@ class PriceReportsController < ApplicationController
# Only allow a list of trusted parameters through. # Only allow a list of trusted parameters through.
def price_report_params def price_report_params
params.expect(price_report: [ :price, :discount_price, :upvotes, :downvotes, :reported_at, :product_id, :store_id, :guest_id ]) params.require(:price_report).permit(:price, :discount_price, :store_id)
end end
end end

View file

@ -9,4 +9,5 @@
# #
class Chain < ApplicationRecord class Chain < ApplicationRecord
has_one_attached :image has_one_attached :image
has_many :stores, dependent: :destroy
end end

View file

@ -0,0 +1,42 @@
# frozen_string_literal: true
module Votable
extend ActiveSupport::Concern
included do
has_many :votes, as: :votable, dependent: :destroy
end
def upvote!(user)
vote = votes.find_by(user:)
if vote
if vote.upvote?
vote.destroy!
else
vote.update!(direction: :upvote)
end
else
Vote.create!(user: user, votable: self, direction: :upvote)
end
end
def downvote!(user)
vote = votes.find_by(user:)
if vote
if vote.downvote?
vote.destroy!
else
vote.update!(direction: :downvote)
end
else
Vote.create!(user: user, votable: self, direction: :downvote)
end
end
def upvote_count
votes.where(direction: :upvote).count
end
def downvote_count
votes.where(direction: :downvote).count
end
end

View file

@ -1,12 +0,0 @@
# == Schema Information
#
# Table name: guests
#
# id :bigint not null, primary key
# name :string
# username :string
# created_at :datetime not null
# updated_at :datetime not null
#
class Guest < ApplicationRecord
end

View file

@ -7,7 +7,7 @@
# reason :string # reason :string
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# admin_id :integer not null # admin_id :bigint not null
# moderatable_id :integer not null # moderatable_id :integer not null
# #
# Indexes # Indexes
@ -17,9 +17,9 @@
# #
# Foreign Keys # Foreign Keys
# #
# fk_rails_... (admin_id => admins.id) # fk_rails_... (admin_id => users.id)
# #
class ModerationLog < ApplicationRecord class ModerationLog < ApplicationRecord
belongs_to :moderatable, polymorphic: true belongs_to :moderatable, polymorphic: true
belongs_to :admin belongs_to :user, foreign_key: :admin_id
end end

View file

@ -4,30 +4,32 @@
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# discount_price :decimal(, ) # discount_price :decimal(, )
# downvotes :integer
# price :decimal(, ) # price :decimal(, )
# reported_at :datetime # reported_at :datetime
# upvotes :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# guest_id :integer not null
# product_id :integer not null # product_id :integer not null
# store_id :integer not null # store_id :integer not null
# user_id :bigint not null
# #
# Indexes # Indexes
# #
# index_price_reports_on_guest_id (guest_id)
# index_price_reports_on_product_id (product_id) # index_price_reports_on_product_id (product_id)
# index_price_reports_on_store_id (store_id) # index_price_reports_on_store_id (store_id)
# index_price_reports_on_user_id (user_id)
# #
# Foreign Keys # Foreign Keys
# #
# fk_rails_... (guest_id => guests.id)
# fk_rails_... (product_id => products.id) # fk_rails_... (product_id => products.id)
# fk_rails_... (store_id => stores.id) # fk_rails_... (store_id => stores.id)
# fk_rails_... (user_id => users.id)
# #
class PriceReport < ApplicationRecord class PriceReport < ApplicationRecord
include Votable
belongs_to :product belongs_to :product
belongs_to :store belongs_to :store
belongs_to :guest belongs_to :user
has_many :moderation_logs, as: :moderatable, dependent: :destroy
end end

View file

@ -14,4 +14,5 @@
# #
class Product < ApplicationRecord class Product < ApplicationRecord
has_one_attached :image has_one_attached :image
has_many :price_reports, dependent: :destroy
end end

View file

@ -21,4 +21,5 @@
class Store < ApplicationRecord class Store < ApplicationRecord
has_one_attached :image has_one_attached :image
belongs_to :chain belongs_to :chain
has_many :price_reports, dependent: :destroy
end end

View file

@ -1,17 +1,21 @@
# == Schema Information # == Schema Information
# #
# Table name: admins # Table name: users
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# email :string # email :string
# name :string # name :string
# password_digest :string # password_digest :string
# role :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# #
# Indexes # Indexes
# #
# index_admins_on_email (email) UNIQUE # index_users_on_email (email) UNIQUE
# #
class Admin < ApplicationRecord class User < ApplicationRecord
has_secure_password
has_many :price_reports, dependent: :nullify
has_many :moderation_logs, foreign_key: :admin_id, dependent: :nullify
end end

29
app/models/vote.rb Normal file
View file

@ -0,0 +1,29 @@
# == Schema Information
#
# Table name: votes
#
# id :bigint not null, primary key
# direction :integer
# votable_type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# user_id :bigint not null
# votable_id :bigint not null
#
# Indexes
#
# index_votes_on_user_id (user_id)
# index_votes_on_votable (votable_type,votable_id)
#
# Foreign Keys
#
# fk_rails_... (user_id => users.id)
#
class Vote < ApplicationRecord
belongs_to :user
belongs_to :votable, polymorphic: true, counter_cache: true
enum :direction, {upvote: 0, downvote: 1}
validates :user_id, uniqueness: { scope: [:votable_type, :votable_id], message: "has already voted on this item" }
end

View file

@ -1,9 +1,11 @@
Rails.application.routes.draw do Rails.application.routes.draw do
resources :price_reports resources :price_reports, only: [:show, :update, :destroy]
resources :guests resources :users
resources :stores resources :stores
resources :chains resources :chains
resources :products resources :products do
resources :price_reports, only: [:index, :create]
end
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.

View file

@ -0,0 +1,13 @@
class CreateUsers < ActiveRecord::Migration[8.0]
def change
create_table :users do |t|
t.string :email
t.string :name
t.string :password_digest
t.integer :role
t.timestamps
end
add_index :users, :email, unique: true
end
end

View file

@ -0,0 +1,17 @@
class DropGuestsAndAdmins < ActiveRecord::Migration[8.0]
def change
remove_foreign_key :price_reports, :guests
remove_foreign_key :moderation_logs, :admins
change_column :price_reports, :guest_id, :bigint
change_column :moderation_logs, :admin_id, :bigint
drop_table :admins
drop_table :guests
rename_column :price_reports, :guest_id, :user_id
add_foreign_key :price_reports, :users
add_foreign_key :moderation_logs, :users, column: :admin_id
end
end

View file

@ -0,0 +1,11 @@
class CreateVotes < ActiveRecord::Migration[8.0]
def change
create_table :votes do |t|
t.references :user, null: false, foreign_key: true
t.references :votable, polymorphic: true, null: false
t.integer :direction
t.timestamps
end
end
end

View file

@ -0,0 +1,6 @@
class ChangeVotingMechanism < ActiveRecord::Migration[8.0]
def change
remove_column :price_reports, :upvotes
remove_column :price_reports, :downvotes
end
end

View file

@ -0,0 +1,6 @@
class AddTokenToUsers < ActiveRecord::Migration[8.0]
def change
add_column :users, :token, :string
add_index :users, :token, unique: true
end
end

52
db/schema.rb generated
View file

@ -10,7 +10,7 @@
# #
# 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[8.0].define(version: 2026_05_17_111138) do ActiveRecord::Schema[8.0].define(version: 2026_05_30_204821) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "pg_catalog.plpgsql" enable_extension "pg_catalog.plpgsql"
@ -42,33 +42,17 @@ ActiveRecord::Schema[8.0].define(version: 2026_05_17_111138) do
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
end end
create_table "admins", force: :cascade do |t|
t.string "name"
t.string "email"
t.string "password_digest"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_admins_on_email", unique: true
end
create_table "chains", force: :cascade do |t| create_table "chains", force: :cascade do |t|
t.string "name" t.string "name"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end end
create_table "guests", force: :cascade do |t|
t.string "username"
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "moderation_logs", force: :cascade do |t| create_table "moderation_logs", force: :cascade do |t|
t.string "reason" t.string "reason"
t.string "moderatable_type", null: false t.string "moderatable_type", null: false
t.integer "moderatable_id", null: false t.integer "moderatable_id", null: false
t.integer "admin_id", null: false t.bigint "admin_id", null: false
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.index ["admin_id"], name: "index_moderation_logs_on_admin_id" t.index ["admin_id"], name: "index_moderation_logs_on_admin_id"
@ -78,17 +62,15 @@ ActiveRecord::Schema[8.0].define(version: 2026_05_17_111138) do
create_table "price_reports", force: :cascade do |t| create_table "price_reports", force: :cascade do |t|
t.decimal "price" t.decimal "price"
t.decimal "discount_price" t.decimal "discount_price"
t.integer "upvotes"
t.integer "downvotes"
t.datetime "reported_at" t.datetime "reported_at"
t.integer "product_id", null: false t.integer "product_id", null: false
t.integer "store_id", null: false t.integer "store_id", null: false
t.integer "guest_id", null: false t.bigint "user_id", null: false
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.index ["guest_id"], name: "index_price_reports_on_guest_id"
t.index ["product_id"], name: "index_price_reports_on_product_id" t.index ["product_id"], name: "index_price_reports_on_product_id"
t.index ["store_id"], name: "index_price_reports_on_store_id" t.index ["store_id"], name: "index_price_reports_on_store_id"
t.index ["user_id"], name: "index_price_reports_on_user_id"
end end
create_table "products", force: :cascade do |t| create_table "products", force: :cascade do |t|
@ -109,11 +91,33 @@ ActiveRecord::Schema[8.0].define(version: 2026_05_17_111138) do
t.index ["chain_id"], name: "index_stores_on_chain_id" t.index ["chain_id"], name: "index_stores_on_chain_id"
end end
create_table "users", force: :cascade do |t|
t.string "email"
t.string "name"
t.string "password_digest"
t.integer "role"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
end
create_table "votes", force: :cascade do |t|
t.bigint "user_id", null: false
t.string "votable_type", null: false
t.bigint "votable_id", null: false
t.integer "direction"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["user_id"], name: "index_votes_on_user_id"
t.index ["votable_type", "votable_id"], name: "index_votes_on_votable"
end
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "moderation_logs", "admins" add_foreign_key "moderation_logs", "users", column: "admin_id"
add_foreign_key "price_reports", "guests"
add_foreign_key "price_reports", "products" add_foreign_key "price_reports", "products"
add_foreign_key "price_reports", "stores" add_foreign_key "price_reports", "stores"
add_foreign_key "price_reports", "users"
add_foreign_key "stores", "chains" add_foreign_key "stores", "chains"
add_foreign_key "votes", "users"
end end

View file

@ -1,38 +0,0 @@
require "test_helper"
class GuestsControllerTest < ActionDispatch::IntegrationTest
setup do
@guest = guests(:one)
end
test "should get index" do
get guests_url, as: :json
assert_response :success
end
test "should create guest" do
assert_difference("Guest.count") do
post guests_url, params: { guest: { name: @guest.name, username: @guest.username } }, as: :json
end
assert_response :created
end
test "should show guest" do
get guest_url(@guest), as: :json
assert_response :success
end
test "should update guest" do
patch guest_url(@guest), params: { guest: { name: @guest.name, username: @guest.username } }, as: :json
assert_response :success
end
test "should destroy guest" do
assert_difference("Guest.count", -1) do
delete guest_url(@guest), as: :json
end
assert_response :no_content
end
end

View file

@ -12,7 +12,7 @@ class PriceReportsControllerTest < ActionDispatch::IntegrationTest
test "should create price_report" do test "should create price_report" do
assert_difference("PriceReport.count") do assert_difference("PriceReport.count") do
post price_reports_url, params: { price_report: { discount_price: @price_report.discount_price, downvotes: @price_report.downvotes, guest_id: @price_report.guest_id, price: @price_report.price, product_id: @price_report.product_id, reported_at: @price_report.reported_at, store_id: @price_report.store_id, upvotes: @price_report.upvotes } }, as: :json post price_reports_url, params: { price_report: { discount_price: @price_report.discount_price, downvotes: @price_report.downvotes, user_id: @price_report.user_id, price: @price_report.price, product_id: @price_report.product_id, reported_at: @price_report.reported_at, store_id: @price_report.store_id, upvotes: @price_report.upvotes } }, as: :json
end end
assert_response :created assert_response :created
@ -24,7 +24,7 @@ class PriceReportsControllerTest < ActionDispatch::IntegrationTest
end end
test "should update price_report" do test "should update price_report" do
patch price_report_url(@price_report), params: { price_report: { discount_price: @price_report.discount_price, downvotes: @price_report.downvotes, guest_id: @price_report.guest_id, price: @price_report.price, product_id: @price_report.product_id, reported_at: @price_report.reported_at, store_id: @price_report.store_id, upvotes: @price_report.upvotes } }, as: :json patch price_report_url(@price_report), params: { price_report: { discount_price: @price_report.discount_price, downvotes: @price_report.downvotes, user_id: @price_report.user_id, price: @price_report.price, product_id: @price_report.product_id, reported_at: @price_report.reported_at, store_id: @price_report.store_id, upvotes: @price_report.upvotes } }, as: :json
assert_response :success assert_response :success
end end

View file

@ -12,7 +12,7 @@ class ProductsControllerTest < ActionDispatch::IntegrationTest
test "should create product" do test "should create product" do
assert_difference("Product.count") do assert_difference("Product.count") do
post products_url, params: { product: { barcode: @product.barcode, name: @product.name } }, as: :json post products_url, params: { product: { barcode: "unique_barcode_123", name: @product.name } }, as: :json
end end
assert_response :created assert_response :created

View file

@ -1,19 +0,0 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
# == Schema Information
#
# Table name: guests
#
# id :bigint not null, primary key
# name :string
# username :string
# created_at :datetime not null
# updated_at :datetime not null
#
one:
username: MyString
name: MyString
two:
username: MyString
name: MyString

View file

@ -9,7 +9,7 @@
# reason :string # reason :string
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# admin_id :integer not null # admin_id :bigint not null
# moderatable_id :integer not null # moderatable_id :integer not null
# #
# Indexes # Indexes
@ -19,16 +19,14 @@
# #
# Foreign Keys # Foreign Keys
# #
# fk_rails_... (admin_id => admins.id) # fk_rails_... (admin_id => users.id)
# #
one: one:
reason: MyString reason: MyString
moderatable: one moderatable: one (Chain)
moderatable_type: Moderatable user: one
admin: one
two: two:
reason: MyString reason: MyString
moderatable: two moderatable: two (Chain)
moderatable_type: Moderatable user: two
admin: two

View file

@ -6,27 +6,25 @@
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# discount_price :decimal(, ) # discount_price :decimal(, )
# downvotes :integer
# price :decimal(, ) # price :decimal(, )
# reported_at :datetime # reported_at :datetime
# upvotes :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# guest_id :integer not null
# product_id :integer not null # product_id :integer not null
# store_id :integer not null # store_id :integer not null
# user_id :bigint not null
# #
# Indexes # Indexes
# #
# index_price_reports_on_guest_id (guest_id)
# index_price_reports_on_product_id (product_id) # index_price_reports_on_product_id (product_id)
# index_price_reports_on_store_id (store_id) # index_price_reports_on_store_id (store_id)
# index_price_reports_on_user_id (user_id)
# #
# Foreign Keys # Foreign Keys
# #
# fk_rails_... (guest_id => guests.id)
# fk_rails_... (product_id => products.id) # fk_rails_... (product_id => products.id)
# fk_rails_... (store_id => stores.id) # fk_rails_... (store_id => stores.id)
# fk_rails_... (user_id => users.id)
# #
one: one:
price: 9.99 price: 9.99
@ -36,7 +34,7 @@ one:
reported_at: 2026-05-17 14:11:07 reported_at: 2026-05-17 14:11:07
product: one product: one
store: one store: one
guest: one user: one
two: two:
price: 9.99 price: 9.99
@ -46,4 +44,4 @@ two:
reported_at: 2026-05-17 14:11:07 reported_at: 2026-05-17 14:11:07
product: two product: two
store: two store: two
guest: two user: two

View file

@ -17,3 +17,7 @@
one: one:
name: MyString name: MyString
barcode: MyString barcode: MyString
two:
name: MyString2
barcode: MyString2

View file

@ -2,25 +2,28 @@
# == Schema Information # == Schema Information
# #
# Table name: admins # Table name: users
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# email :string # email :string
# name :string # name :string
# password_digest :string # password_digest :string
# role :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# #
# Indexes # Indexes
# #
# index_admins_on_email (email) UNIQUE # index_users_on_email (email) UNIQUE
# #
one: one:
name: MyString email: guest@test.com
email: MyString name: Guest
password_digest: MyString password_digest: MyString
role: 0
two: two:
name: MyString email: admin@test.com
email: MyString name: Admin
password_digest: MyString password_digest: MyString
role: 1

32
test/fixtures/votes.yml vendored Normal file
View file

@ -0,0 +1,32 @@
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
# == Schema Information
#
# Table name: votes
#
# id :bigint not null, primary key
# direction :integer
# votable_type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# user_id :bigint not null
# votable_id :bigint not null
#
# Indexes
#
# index_votes_on_user_id (user_id)
# index_votes_on_votable (votable_type,votable_id)
#
# Foreign Keys
#
# fk_rails_... (user_id => users.id)
#
one:
user: one
votable=references{polymorphic}: MyString
direction: 1
two:
user: two
votable=references{polymorphic}: MyString
direction: 1

View file

@ -1,17 +0,0 @@
# == Schema Information
#
# Table name: guests
#
# id :bigint not null, primary key
# name :string
# username :string
# created_at :datetime not null
# updated_at :datetime not null
#
require "test_helper"
class GuestTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end

View file

@ -7,7 +7,7 @@
# reason :string # reason :string
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# admin_id :integer not null # admin_id :bigint not null
# moderatable_id :integer not null # moderatable_id :integer not null
# #
# Indexes # Indexes
@ -17,7 +17,7 @@
# #
# Foreign Keys # Foreign Keys
# #
# fk_rails_... (admin_id => admins.id) # fk_rails_... (admin_id => users.id)
# #
require "test_helper" require "test_helper"

View file

@ -4,27 +4,25 @@
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# discount_price :decimal(, ) # discount_price :decimal(, )
# downvotes :integer
# price :decimal(, ) # price :decimal(, )
# reported_at :datetime # reported_at :datetime
# upvotes :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# guest_id :integer not null
# product_id :integer not null # product_id :integer not null
# store_id :integer not null # store_id :integer not null
# user_id :bigint not null
# #
# Indexes # Indexes
# #
# index_price_reports_on_guest_id (guest_id)
# index_price_reports_on_product_id (product_id) # index_price_reports_on_product_id (product_id)
# index_price_reports_on_store_id (store_id) # index_price_reports_on_store_id (store_id)
# index_price_reports_on_user_id (user_id)
# #
# Foreign Keys # Foreign Keys
# #
# fk_rails_... (guest_id => guests.id)
# fk_rails_... (product_id => products.id) # fk_rails_... (product_id => products.id)
# fk_rails_... (store_id => stores.id) # fk_rails_... (store_id => stores.id)
# fk_rails_... (user_id => users.id)
# #
require "test_helper" require "test_helper"

View file

@ -1,21 +1,22 @@
# == Schema Information # == Schema Information
# #
# Table name: admins # Table name: users
# #
# id :bigint not null, primary key # id :bigint not null, primary key
# email :string # email :string
# name :string # name :string
# password_digest :string # password_digest :string
# role :integer
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# #
# Indexes # Indexes
# #
# index_admins_on_email (email) UNIQUE # index_users_on_email (email) UNIQUE
# #
require "test_helper" require "test_helper"
class AdminTest < ActiveSupport::TestCase class UserTest < ActiveSupport::TestCase
# test "the truth" do # test "the truth" do
# assert true # assert true
# end # end

28
test/models/vote_test.rb Normal file
View file

@ -0,0 +1,28 @@
# == Schema Information
#
# Table name: votes
#
# id :bigint not null, primary key
# direction :integer
# votable_type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# user_id :bigint not null
# votable_id :bigint not null
#
# Indexes
#
# index_votes_on_user_id (user_id)
# index_votes_on_votable (votable_type,votable_id)
#
# Foreign Keys
#
# fk_rails_... (user_id => users.id)
#
require "test_helper"
class VoteTest < ActiveSupport::TestCase
# test "the truth" do
# assert true
# end
end