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

This commit is contained in:
Mohammad Kanaan 2026-05-31 00:27:35 +03:00
parent 5c4667ed02
commit 54bdd52e75
7 changed files with 25 additions and 1 deletions

View file

@ -42,6 +42,7 @@
<orderEntry type="library" scope="TEST" name="annotaterb (v4.22.0, 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="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="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="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="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="bigdecimal (v4.1.2, RVM: ruby-3.4.4) [gem]" level="application" />

View file

@ -5,3 +5,4 @@ ts=2026-05-30T17:25:34.868Z type=preference scope=developer-profile content="Tea
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: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: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-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

@ -15,6 +15,7 @@
# index_users_on_email (email) UNIQUE # index_users_on_email (email) UNIQUE
# #
class User < ApplicationRecord class User < ApplicationRecord
has_secure_password
has_many :price_reports, dependent: :nullify has_many :price_reports, dependent: :nullify
has_many :moderation_logs, foreign_key: :admin_id, dependent: :nullify has_many :moderation_logs, foreign_key: :admin_id, dependent: :nullify
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