From 89b302b7ee9655709d70b555edd4e909bb3459bb Mon Sep 17 00:00:00 2001 From: John Verdone Date: Mon, 12 Aug 2024 14:55:29 -0400 Subject: [PATCH 01/16] use devise to stub out user sing in --- app/views/devise/confirmations/new.html.erb | 16 +++++++ .../mailer/confirmation_instructions.html.erb | 5 +++ .../devise/mailer/email_changed.html.erb | 7 +++ .../devise/mailer/password_change.html.erb | 3 ++ .../reset_password_instructions.html.erb | 8 ++++ .../mailer/unlock_instructions.html.erb | 7 +++ app/views/devise/passwords/edit.html.erb | 25 +++++++++++ app/views/devise/passwords/new.html.erb | 16 +++++++ app/views/devise/registrations/edit.html.erb | 43 +++++++++++++++++++ app/views/devise/registrations/new.html.erb | 29 +++++++++++++ app/views/devise/sessions/new.html.erb | 26 +++++++++++ .../devise/shared/_error_messages.html.erb | 15 +++++++ app/views/devise/shared/_links.html.erb | 25 +++++++++++ app/views/devise/unlocks/new.html.erb | 16 +++++++ 14 files changed, 241 insertions(+) create mode 100644 app/views/devise/confirmations/new.html.erb create mode 100644 app/views/devise/mailer/confirmation_instructions.html.erb create mode 100644 app/views/devise/mailer/email_changed.html.erb create mode 100644 app/views/devise/mailer/password_change.html.erb create mode 100644 app/views/devise/mailer/reset_password_instructions.html.erb create mode 100644 app/views/devise/mailer/unlock_instructions.html.erb create mode 100644 app/views/devise/passwords/edit.html.erb create mode 100644 app/views/devise/passwords/new.html.erb create mode 100644 app/views/devise/registrations/edit.html.erb create mode 100644 app/views/devise/registrations/new.html.erb create mode 100644 app/views/devise/sessions/new.html.erb create mode 100644 app/views/devise/shared/_error_messages.html.erb create mode 100644 app/views/devise/shared/_links.html.erb create mode 100644 app/views/devise/unlocks/new.html.erb diff --git a/app/views/devise/confirmations/new.html.erb b/app/views/devise/confirmations/new.html.erb new file mode 100644 index 00000000..b12dd0cb --- /dev/null +++ b/app/views/devise/confirmations/new.html.erb @@ -0,0 +1,16 @@ +

Resend confirmation instructions

+ +<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %> + <%= render "devise/shared/error_messages", resource: resource %> + +
+ <%= f.label :email %>
+ <%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %> +
+ +
+ <%= f.submit "Resend confirmation instructions" %> +
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb new file mode 100644 index 00000000..dc55f64f --- /dev/null +++ b/app/views/devise/mailer/confirmation_instructions.html.erb @@ -0,0 +1,5 @@ +

Welcome <%= @email %>!

+ +

You can confirm your account email through the link below:

+ +

<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>

diff --git a/app/views/devise/mailer/email_changed.html.erb b/app/views/devise/mailer/email_changed.html.erb new file mode 100644 index 00000000..32f4ba80 --- /dev/null +++ b/app/views/devise/mailer/email_changed.html.erb @@ -0,0 +1,7 @@ +

Hello <%= @email %>!

+ +<% if @resource.try(:unconfirmed_email?) %> +

We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.

+<% else %> +

We're contacting you to notify you that your email has been changed to <%= @resource.email %>.

+<% end %> diff --git a/app/views/devise/mailer/password_change.html.erb b/app/views/devise/mailer/password_change.html.erb new file mode 100644 index 00000000..b41daf47 --- /dev/null +++ b/app/views/devise/mailer/password_change.html.erb @@ -0,0 +1,3 @@ +

Hello <%= @resource.email %>!

+ +

We're contacting you to notify you that your password has been changed.

diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb new file mode 100644 index 00000000..f667dc12 --- /dev/null +++ b/app/views/devise/mailer/reset_password_instructions.html.erb @@ -0,0 +1,8 @@ +

Hello <%= @resource.email %>!

+ +

Someone has requested a link to change your password. You can do this through the link below.

+ +

<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>

+ +

If you didn't request this, please ignore this email.

+

Your password won't change until you access the link above and create a new one.

diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb new file mode 100644 index 00000000..41e148bf --- /dev/null +++ b/app/views/devise/mailer/unlock_instructions.html.erb @@ -0,0 +1,7 @@ +

Hello <%= @resource.email %>!

+ +

Your account has been locked due to an excessive number of unsuccessful sign in attempts.

+ +

Click the link below to unlock your account:

+ +

<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>

diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb new file mode 100644 index 00000000..5fbb9ff0 --- /dev/null +++ b/app/views/devise/passwords/edit.html.erb @@ -0,0 +1,25 @@ +

Change your password

+ +<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> + <%= render "devise/shared/error_messages", resource: resource %> + <%= f.hidden_field :reset_password_token %> + +
+ <%= f.label :password, "New password" %>
+ <% if @minimum_password_length %> + (<%= @minimum_password_length %> characters minimum)
+ <% end %> + <%= f.password_field :password, autofocus: true, autocomplete: "new-password" %> +
+ +
+ <%= f.label :password_confirmation, "Confirm new password" %>
+ <%= f.password_field :password_confirmation, autocomplete: "new-password" %> +
+ +
+ <%= f.submit "Change my password" %> +
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb new file mode 100644 index 00000000..9b486b81 --- /dev/null +++ b/app/views/devise/passwords/new.html.erb @@ -0,0 +1,16 @@ +

Forgot your password?

+ +<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %> + <%= render "devise/shared/error_messages", resource: resource %> + +
+ <%= f.label :email %>
+ <%= f.email_field :email, autofocus: true, autocomplete: "email" %> +
+ +
+ <%= f.submit "Send me reset password instructions" %> +
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb new file mode 100644 index 00000000..b82e3365 --- /dev/null +++ b/app/views/devise/registrations/edit.html.erb @@ -0,0 +1,43 @@ +

Edit <%= resource_name.to_s.humanize %>

+ +<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> + <%= render "devise/shared/error_messages", resource: resource %> + +
+ <%= f.label :email %>
+ <%= f.email_field :email, autofocus: true, autocomplete: "email" %> +
+ + <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> +
Currently waiting confirmation for: <%= resource.unconfirmed_email %>
+ <% end %> + +
+ <%= f.label :password %> (leave blank if you don't want to change it)
+ <%= f.password_field :password, autocomplete: "new-password" %> + <% if @minimum_password_length %> +
+ <%= @minimum_password_length %> characters minimum + <% end %> +
+ +
+ <%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation, autocomplete: "new-password" %> +
+ +
+ <%= f.label :current_password %> (we need your current password to confirm your changes)
+ <%= f.password_field :current_password, autocomplete: "current-password" %> +
+ +
+ <%= f.submit "Update" %> +
+<% end %> + +

Cancel my account

+ +
Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %>
+ +<%= link_to "Back", :back %> diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb new file mode 100644 index 00000000..d655b66f --- /dev/null +++ b/app/views/devise/registrations/new.html.erb @@ -0,0 +1,29 @@ +

Sign up

+ +<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> + <%= render "devise/shared/error_messages", resource: resource %> + +
+ <%= f.label :email %>
+ <%= f.email_field :email, autofocus: true, autocomplete: "email" %> +
+ +
+ <%= f.label :password %> + <% if @minimum_password_length %> + (<%= @minimum_password_length %> characters minimum) + <% end %>
+ <%= f.password_field :password, autocomplete: "new-password" %> +
+ +
+ <%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation, autocomplete: "new-password" %> +
+ +
+ <%= f.submit "Sign up" %> +
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb new file mode 100644 index 00000000..5ede9648 --- /dev/null +++ b/app/views/devise/sessions/new.html.erb @@ -0,0 +1,26 @@ +

Log in

+ +<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> +
+ <%= f.label :email %>
+ <%= f.email_field :email, autofocus: true, autocomplete: "email" %> +
+ +
+ <%= f.label :password %>
+ <%= f.password_field :password, autocomplete: "current-password" %> +
+ + <% if devise_mapping.rememberable? %> +
+ <%= f.check_box :remember_me %> + <%= f.label :remember_me %> +
+ <% end %> + +
+ <%= f.submit "Log in" %> +
+<% end %> + +<%= render "devise/shared/links" %> diff --git a/app/views/devise/shared/_error_messages.html.erb b/app/views/devise/shared/_error_messages.html.erb new file mode 100644 index 00000000..cabfe307 --- /dev/null +++ b/app/views/devise/shared/_error_messages.html.erb @@ -0,0 +1,15 @@ +<% if resource.errors.any? %> +
+

+ <%= I18n.t("errors.messages.not_saved", + count: resource.errors.count, + resource: resource.class.model_name.human.downcase) + %> +

+ +
+<% end %> diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb new file mode 100644 index 00000000..7a75304b --- /dev/null +++ b/app/views/devise/shared/_links.html.erb @@ -0,0 +1,25 @@ +<%- if controller_name != 'sessions' %> + <%= link_to "Log in", new_session_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.registerable? && controller_name != 'registrations' %> + <%= link_to "Sign up", new_registration_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> + <%= link_to "Forgot your password?", new_password_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> + <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> + <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.omniauthable? %> + <%- resource_class.omniauth_providers.each do |provider| %> + <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %>
+ <% end %> +<% end %> diff --git a/app/views/devise/unlocks/new.html.erb b/app/views/devise/unlocks/new.html.erb new file mode 100644 index 00000000..ffc34de8 --- /dev/null +++ b/app/views/devise/unlocks/new.html.erb @@ -0,0 +1,16 @@ +

Resend unlock instructions

+ +<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %> + <%= render "devise/shared/error_messages", resource: resource %> + +
+ <%= f.label :email %>
+ <%= f.email_field :email, autofocus: true, autocomplete: "email" %> +
+ +
+ <%= f.submit "Resend unlock instructions" %> +
+<% end %> + +<%= render "devise/shared/links" %> From 41605e7cbf271a2bf4d370930f5748d462d83b72 Mon Sep 17 00:00:00 2001 From: John Verdone Date: Mon, 12 Aug 2024 14:55:47 -0400 Subject: [PATCH 02/16] update and run bundle install --- Gemfile.lock | 295 ++++++++++++++++++++++++----------------------- Gemfile.lock.old | 288 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 436 insertions(+), 147 deletions(-) create mode 100644 Gemfile.lock.old diff --git a/Gemfile.lock b/Gemfile.lock index 14ec6457..bdf4f273 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,87 +1,87 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.0.4) - actionpack (= 7.0.4) - activesupport (= 7.0.4) + actioncable (7.0.8.4) + actionpack (= 7.0.8.4) + activesupport (= 7.0.8.4) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (7.0.4) - actionpack (= 7.0.4) - activejob (= 7.0.4) - activerecord (= 7.0.4) - activestorage (= 7.0.4) - activesupport (= 7.0.4) + actionmailbox (7.0.8.4) + actionpack (= 7.0.8.4) + activejob (= 7.0.8.4) + activerecord (= 7.0.8.4) + activestorage (= 7.0.8.4) + activesupport (= 7.0.8.4) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.0.4) - actionpack (= 7.0.4) - actionview (= 7.0.4) - activejob (= 7.0.4) - activesupport (= 7.0.4) + actionmailer (7.0.8.4) + actionpack (= 7.0.8.4) + actionview (= 7.0.8.4) + activejob (= 7.0.8.4) + activesupport (= 7.0.8.4) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.0) - actionpack (7.0.4) - actionview (= 7.0.4) - activesupport (= 7.0.4) - rack (~> 2.0, >= 2.2.0) + actionpack (7.0.8.4) + actionview (= 7.0.8.4) + activesupport (= 7.0.8.4) + rack (~> 2.0, >= 2.2.4) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (7.0.4) - actionpack (= 7.0.4) - activerecord (= 7.0.4) - activestorage (= 7.0.4) - activesupport (= 7.0.4) + actiontext (7.0.8.4) + actionpack (= 7.0.8.4) + activerecord (= 7.0.8.4) + activestorage (= 7.0.8.4) + activesupport (= 7.0.8.4) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.0.4) - activesupport (= 7.0.4) + actionview (7.0.8.4) + activesupport (= 7.0.8.4) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (7.0.4) - activesupport (= 7.0.4) + activejob (7.0.8.4) + activesupport (= 7.0.8.4) globalid (>= 0.3.6) - activemodel (7.0.4) - activesupport (= 7.0.4) - activerecord (7.0.4) - activemodel (= 7.0.4) - activesupport (= 7.0.4) - activestorage (7.0.4) - actionpack (= 7.0.4) - activejob (= 7.0.4) - activerecord (= 7.0.4) - activesupport (= 7.0.4) + activemodel (7.0.8.4) + activesupport (= 7.0.8.4) + activerecord (7.0.8.4) + activemodel (= 7.0.8.4) + activesupport (= 7.0.8.4) + activestorage (7.0.8.4) + actionpack (= 7.0.8.4) + activejob (= 7.0.8.4) + activerecord (= 7.0.8.4) + activesupport (= 7.0.8.4) marcel (~> 1.0) mini_mime (>= 1.1.0) - activesupport (7.0.4) + activesupport (7.0.8.4) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.1) - public_suffix (>= 2.0.2, < 6.0) - bcrypt (3.1.18) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + base64 (0.2.0) + bcrypt (3.1.20) bindex (0.8.1) - builder (3.2.4) + builder (3.3.0) byebug (11.1.3) - capybara (3.37.1) + capybara (3.40.0) addressable matrix mini_mime (>= 0.1.3) - nokogiri (~> 1.8) + nokogiri (~> 1.11) rack (>= 1.6.0) rack-test (>= 0.6.3) regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) - childprocess (4.1.0) coderay (1.1.3) coffee-rails (5.0.0) coffee-script (>= 2.2.0) @@ -90,124 +90,124 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - concurrent-ruby (1.1.10) + concurrent-ruby (1.3.3) crass (1.0.6) - devise (4.8.1) + date (3.3.4) + devise (4.9.4) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 4.1.0) responders warden (~> 1.2.3) - diff-lcs (1.5.0) - digest (3.1.0) - erubi (1.11.0) - execjs (2.8.1) - ffi (1.15.5) - globalid (1.0.0) - activesupport (>= 5.0) - i18n (1.12.0) + diff-lcs (1.5.1) + erubi (1.13.0) + execjs (2.9.1) + ffi (1.17.0-x86_64-darwin) + globalid (1.2.1) + activesupport (>= 6.1) + i18n (1.14.5) concurrent-ruby (~> 1.0) - jbuilder (2.11.5) + jbuilder (2.12.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) - listen (3.7.1) + listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - loofah (2.19.0) + logger (1.6.0) + loofah (2.22.0) crass (~> 1.0.2) - nokogiri (>= 1.5.9) - mail (2.7.1) + nokogiri (>= 1.12.0) + mail (2.8.1) mini_mime (>= 0.1.1) - marcel (1.0.2) + net-imap + net-pop + net-smtp + marcel (1.0.4) matrix (0.4.2) - method_source (1.0.0) - mini_mime (1.1.2) - mini_portile2 (2.8.0) - minitest (5.16.3) - net-imap (0.2.3) - digest + method_source (1.1.0) + mini_mime (1.1.5) + minitest (5.24.1) + net-imap (0.4.14) + date net-protocol - strscan - net-pop (0.1.1) - digest + net-pop (0.1.2) net-protocol + net-protocol (0.2.2) timeout - net-protocol (0.1.3) - timeout - net-smtp (0.3.1) - digest + net-smtp (0.5.0) net-protocol - timeout - nio4r (2.5.8) - nokogiri (1.13.8) - mini_portile2 (~> 2.8.0) + nio4r (2.7.3) + nokogiri (1.16.7-x86_64-darwin) racc (~> 1.4) orm_adapter (0.5.0) - pg (1.4.3) - pry (0.14.1) + pg (1.5.7) + pry (0.14.2) coderay (~> 1.1) method_source (~> 1.0) - pry-rails (0.3.9) - pry (>= 0.10.4) - public_suffix (5.0.0) - puma (5.6.5) + pry-rails (0.3.11) + pry (>= 0.13.0) + public_suffix (6.0.1) + puma (6.4.2) nio4r (~> 2.0) - racc (1.6.0) - rack (2.2.4) - rack-test (2.0.2) + racc (1.8.1) + rack (2.2.9) + rack-test (2.1.0) rack (>= 1.3) - rails (7.0.4) - actioncable (= 7.0.4) - actionmailbox (= 7.0.4) - actionmailer (= 7.0.4) - actionpack (= 7.0.4) - actiontext (= 7.0.4) - actionview (= 7.0.4) - activejob (= 7.0.4) - activemodel (= 7.0.4) - activerecord (= 7.0.4) - activestorage (= 7.0.4) - activesupport (= 7.0.4) + rails (7.0.8.4) + actioncable (= 7.0.8.4) + actionmailbox (= 7.0.8.4) + actionmailer (= 7.0.8.4) + actionpack (= 7.0.8.4) + actiontext (= 7.0.8.4) + actionview (= 7.0.8.4) + activejob (= 7.0.8.4) + activemodel (= 7.0.8.4) + activerecord (= 7.0.8.4) + activestorage (= 7.0.8.4) + activesupport (= 7.0.8.4) bundler (>= 1.15.0) - railties (= 7.0.4) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) + railties (= 7.0.8.4) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.4.3) - loofah (~> 2.3) - railties (7.0.4) - actionpack (= 7.0.4) - activesupport (= 7.0.4) + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) + railties (7.0.8.4) + actionpack (= 7.0.8.4) + activesupport (= 7.0.8.4) method_source rake (>= 12.2) thor (~> 1.0) zeitwerk (~> 2.5) - rake (13.0.6) + rake (13.2.1) rb-fsevent (0.11.2) - rb-inotify (0.10.1) + rb-inotify (0.11.1) ffi (~> 1.0) - regexp_parser (2.5.0) - responders (3.0.1) - actionpack (>= 5.0) - railties (>= 5.0) - rexml (3.2.5) - rspec-core (3.11.0) - rspec-support (~> 3.11.0) - rspec-expectations (3.11.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) - rspec-mocks (3.11.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.11.0) - rspec-rails (5.1.2) + regexp_parser (2.9.2) + responders (3.1.1) actionpack (>= 5.2) - activesupport (>= 5.2) railties (>= 5.2) - rspec-core (~> 3.10) - rspec-expectations (~> 3.10) - rspec-mocks (~> 3.10) - rspec-support (~> 3.10) - rspec-support (3.11.1) + rexml (3.3.4) + strscan + rspec-core (3.13.0) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-rails (6.1.3) + actionpack (>= 6.1) + activesupport (>= 6.1) + railties (>= 6.1) + rspec-core (~> 3.13) + rspec-expectations (~> 3.13) + rspec-mocks (~> 3.13) + rspec-support (~> 3.13) + rspec-support (3.13.1) rubyzip (2.3.2) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) @@ -219,47 +219,48 @@ GEM sprockets (> 3.0) sprockets-rails tilt - selenium-webdriver (4.4.0) - childprocess (>= 0.5, < 5.0) + selenium-webdriver (4.23.0) + base64 (~> 0.2) + logger (~> 1.4) rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) - spring (4.1.0) - sprockets (4.1.1) + spring (4.2.1) + sprockets (4.2.1) concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) + rack (>= 2.2.4, < 4) + sprockets-rails (3.5.2) + actionpack (>= 6.1) + activesupport (>= 6.1) sprockets (>= 3.0.0) - strscan (3.0.4) - thor (1.2.1) - tilt (2.0.11) - timeout (0.3.0) + strscan (3.1.0) + thor (1.3.1) + tilt (2.4.0) + timeout (0.4.1) turbolinks (5.2.1) turbolinks-source (~> 5.2) turbolinks-source (5.2.0) - tzinfo (2.0.5) + tzinfo (2.0.6) concurrent-ruby (~> 1.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) warden (1.2.9) rack (>= 2.0.9) - web-console (4.2.0) + web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - websocket (1.2.9) - websocket-driver (0.7.5) + websocket (1.2.11) + websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.6.0) + zeitwerk (2.6.17) PLATFORMS - ruby + x86_64-darwin-23 DEPENDENCIES byebug diff --git a/Gemfile.lock.old b/Gemfile.lock.old new file mode 100644 index 00000000..14ec6457 --- /dev/null +++ b/Gemfile.lock.old @@ -0,0 +1,288 @@ +GEM + remote: https://rubygems.org/ + specs: + actioncable (7.0.4) + actionpack (= 7.0.4) + activesupport (= 7.0.4) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (7.0.4) + actionpack (= 7.0.4) + activejob (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.0.4) + actionpack (= 7.0.4) + actionview (= 7.0.4) + activejob (= 7.0.4) + activesupport (= 7.0.4) + mail (~> 2.5, >= 2.5.4) + net-imap + net-pop + net-smtp + rails-dom-testing (~> 2.0) + actionpack (7.0.4) + actionview (= 7.0.4) + activesupport (= 7.0.4) + rack (~> 2.0, >= 2.2.0) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (7.0.4) + actionpack (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.0.4) + activesupport (= 7.0.4) + builder (~> 3.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (7.0.4) + activesupport (= 7.0.4) + globalid (>= 0.3.6) + activemodel (7.0.4) + activesupport (= 7.0.4) + activerecord (7.0.4) + activemodel (= 7.0.4) + activesupport (= 7.0.4) + activestorage (7.0.4) + actionpack (= 7.0.4) + activejob (= 7.0.4) + activerecord (= 7.0.4) + activesupport (= 7.0.4) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (7.0.4) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + addressable (2.8.1) + public_suffix (>= 2.0.2, < 6.0) + bcrypt (3.1.18) + bindex (0.8.1) + builder (3.2.4) + byebug (11.1.3) + capybara (3.37.1) + addressable + matrix + mini_mime (>= 0.1.3) + nokogiri (~> 1.8) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) + childprocess (4.1.0) + coderay (1.1.3) + coffee-rails (5.0.0) + coffee-script (>= 2.2.0) + railties (>= 5.2.0) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.12.2) + concurrent-ruby (1.1.10) + crass (1.0.6) + devise (4.8.1) + bcrypt (~> 3.0) + orm_adapter (~> 0.1) + railties (>= 4.1.0) + responders + warden (~> 1.2.3) + diff-lcs (1.5.0) + digest (3.1.0) + erubi (1.11.0) + execjs (2.8.1) + ffi (1.15.5) + globalid (1.0.0) + activesupport (>= 5.0) + i18n (1.12.0) + concurrent-ruby (~> 1.0) + jbuilder (2.11.5) + actionview (>= 5.0.0) + activesupport (>= 5.0.0) + listen (3.7.1) + rb-fsevent (~> 0.10, >= 0.10.3) + rb-inotify (~> 0.9, >= 0.9.10) + loofah (2.19.0) + crass (~> 1.0.2) + nokogiri (>= 1.5.9) + mail (2.7.1) + mini_mime (>= 0.1.1) + marcel (1.0.2) + matrix (0.4.2) + method_source (1.0.0) + mini_mime (1.1.2) + mini_portile2 (2.8.0) + minitest (5.16.3) + net-imap (0.2.3) + digest + net-protocol + strscan + net-pop (0.1.1) + digest + net-protocol + timeout + net-protocol (0.1.3) + timeout + net-smtp (0.3.1) + digest + net-protocol + timeout + nio4r (2.5.8) + nokogiri (1.13.8) + mini_portile2 (~> 2.8.0) + racc (~> 1.4) + orm_adapter (0.5.0) + pg (1.4.3) + pry (0.14.1) + coderay (~> 1.1) + method_source (~> 1.0) + pry-rails (0.3.9) + pry (>= 0.10.4) + public_suffix (5.0.0) + puma (5.6.5) + nio4r (~> 2.0) + racc (1.6.0) + rack (2.2.4) + rack-test (2.0.2) + rack (>= 1.3) + rails (7.0.4) + actioncable (= 7.0.4) + actionmailbox (= 7.0.4) + actionmailer (= 7.0.4) + actionpack (= 7.0.4) + actiontext (= 7.0.4) + actionview (= 7.0.4) + activejob (= 7.0.4) + activemodel (= 7.0.4) + activerecord (= 7.0.4) + activestorage (= 7.0.4) + activesupport (= 7.0.4) + bundler (>= 1.15.0) + railties (= 7.0.4) + rails-dom-testing (2.0.3) + activesupport (>= 4.2.0) + nokogiri (>= 1.6) + rails-html-sanitizer (1.4.3) + loofah (~> 2.3) + railties (7.0.4) + actionpack (= 7.0.4) + activesupport (= 7.0.4) + method_source + rake (>= 12.2) + thor (~> 1.0) + zeitwerk (~> 2.5) + rake (13.0.6) + rb-fsevent (0.11.2) + rb-inotify (0.10.1) + ffi (~> 1.0) + regexp_parser (2.5.0) + responders (3.0.1) + actionpack (>= 5.0) + railties (>= 5.0) + rexml (3.2.5) + rspec-core (3.11.0) + rspec-support (~> 3.11.0) + rspec-expectations (3.11.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.11.0) + rspec-mocks (3.11.1) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.11.0) + rspec-rails (5.1.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + railties (>= 5.2) + rspec-core (~> 3.10) + rspec-expectations (~> 3.10) + rspec-mocks (~> 3.10) + rspec-support (~> 3.10) + rspec-support (3.11.1) + rubyzip (2.3.2) + sass-rails (6.0.0) + sassc-rails (~> 2.1, >= 2.1.1) + sassc (2.4.0) + ffi (~> 1.9) + sassc-rails (2.1.2) + railties (>= 4.0.0) + sassc (>= 2.0) + sprockets (> 3.0) + sprockets-rails + tilt + selenium-webdriver (4.4.0) + childprocess (>= 0.5, < 5.0) + rexml (~> 3.2, >= 3.2.5) + rubyzip (>= 1.2.2, < 3.0) + websocket (~> 1.0) + spring (4.1.0) + sprockets (4.1.1) + concurrent-ruby (~> 1.0) + rack (> 1, < 3) + sprockets-rails (3.4.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + sprockets (>= 3.0.0) + strscan (3.0.4) + thor (1.2.1) + tilt (2.0.11) + timeout (0.3.0) + turbolinks (5.2.1) + turbolinks-source (~> 5.2) + turbolinks-source (5.2.0) + tzinfo (2.0.5) + concurrent-ruby (~> 1.0) + uglifier (4.2.0) + execjs (>= 0.3.0, < 3) + warden (1.2.9) + rack (>= 2.0.9) + web-console (4.2.0) + actionview (>= 6.0.0) + activemodel (>= 6.0.0) + bindex (>= 0.4.0) + railties (>= 6.0.0) + websocket (1.2.9) + websocket-driver (0.7.5) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) + zeitwerk (2.6.0) + +PLATFORMS + ruby + +DEPENDENCIES + byebug + capybara + coffee-rails + devise + jbuilder + listen + pg + pry-rails + puma + rails (~> 7.0.3) + rspec-rails + sass-rails + selenium-webdriver + spring + turbolinks + tzinfo-data + uglifier + web-console + +RUBY VERSION + ruby 3.1.2p20 + +BUNDLED WITH + 2.3.22 From 019bbdd8e28ece908448d22761d25d53f4689652 Mon Sep 17 00:00:00 2001 From: John Verdone Date: Mon, 12 Aug 2024 23:39:30 -0400 Subject: [PATCH 03/16] stubbed out sidekiq job to get HN data. Set up services to add new details of stories to DB --- Gemfile | 24 ++++++++--- Gemfile.lock | 23 ++++++++++ app/models/news_detail.rb | 6 +++ app/services/hacker_news/and_new_stories.rb | 33 ++++++++++++++ app/services/hacker_news/base.rb | 29 +++++++++++++ .../hacker_news/create_item_detail.rb | 43 +++++++++++++++++++ app/sidekiq/poll_hacker_news_job.rb | 23 ++++++++++ config/application.rb | 2 + config/initializers/sidekiq.rb | 10 +++++ config/sidekiq_scheduler.yml | 4 ++ .../20240812194904_create_news_details.rb | 14 ++++++ db/schema.rb | 14 +++++- spec/jobs/poll_hacker_news_job_spec.rb | 5 +++ spec/sidekiq/hard_job_spec.rb | 4 ++ spec/sidekiq/poll_hacker_news_job_spec.rb | 4 ++ 15 files changed, 231 insertions(+), 7 deletions(-) create mode 100644 app/models/news_detail.rb create mode 100644 app/services/hacker_news/and_new_stories.rb create mode 100644 app/services/hacker_news/base.rb create mode 100644 app/services/hacker_news/create_item_detail.rb create mode 100644 app/sidekiq/poll_hacker_news_job.rb create mode 100644 config/initializers/sidekiq.rb create mode 100644 config/sidekiq_scheduler.yml create mode 100644 db/migrate/20240812194904_create_news_details.rb create mode 100644 spec/jobs/poll_hacker_news_job_spec.rb create mode 100644 spec/sidekiq/hard_job_spec.rb create mode 100644 spec/sidekiq/poll_hacker_news_job_spec.rb diff --git a/Gemfile b/Gemfile index 5a8ffc43..766fca96 100644 --- a/Gemfile +++ b/Gemfile @@ -2,21 +2,33 @@ source 'https://rubygems.org' ruby File.read('.ruby-version').chomp -gem 'byebug', platforms: [:mri, :mingw, :x64_mingw], group: [:development, :test] -gem 'capybara', group: [:development, :test] gem 'coffee-rails' gem 'devise' gem 'jbuilder' -gem 'listen', group: :development gem 'pg' gem 'pry-rails' gem 'puma' gem 'rails', '~> 7.0.3' gem 'rspec-rails' gem 'sass-rails' -gem 'selenium-webdriver', group: [:development, :test] -gem 'spring', group: :development gem 'turbolinks' gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] gem 'uglifier' -gem 'web-console', group: :development +gem 'sidekiq' +gem 'sidekiq-scheduler', '~> 4.0' +gem 'redis' + + + +group :development do + gem 'spring' + gem 'web-console' + gem 'listen' +end + +group :development, :test do + gem 'selenium-webdriver' + gem 'pry' + gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] + gem 'capybara' +end \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index bdf4f273..f9ea4334 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -91,6 +91,7 @@ GEM execjs coffee-script-source (1.12.2) concurrent-ruby (1.3.3) + connection_pool (2.4.1) crass (1.0.6) date (3.3.4) devise (4.9.4) @@ -101,8 +102,13 @@ GEM warden (~> 1.2.3) diff-lcs (1.5.1) erubi (1.13.0) + et-orbi (1.2.11) + tzinfo execjs (2.9.1) ffi (1.17.0-x86_64-darwin) + fugit (1.11.0) + et-orbi (~> 1, >= 1.2.11) + raabro (~> 1.4) globalid (1.2.1) activesupport (>= 6.1) i18n (1.14.5) @@ -149,6 +155,7 @@ GEM public_suffix (6.0.1) puma (6.4.2) nio4r (~> 2.0) + raabro (1.4.0) racc (1.8.1) rack (2.2.9) rack-test (2.1.0) @@ -185,6 +192,7 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) + redis (4.8.1) regexp_parser (2.9.2) responders (3.1.1) actionpack (>= 5.2) @@ -209,6 +217,8 @@ GEM rspec-support (~> 3.13) rspec-support (3.13.1) rubyzip (2.3.2) + rufus-scheduler (3.9.1) + fugit (~> 1.1, >= 1.1.6) sass-rails (6.0.0) sassc-rails (~> 2.1, >= 2.1.1) sassc (2.4.0) @@ -225,6 +235,15 @@ GEM rexml (~> 3.2, >= 3.2.5) rubyzip (>= 1.2.2, < 3.0) websocket (~> 1.0) + sidekiq (6.5.12) + connection_pool (>= 2.2.5, < 3) + rack (~> 2.0) + redis (>= 4.5.0, < 5) + sidekiq-scheduler (4.0.3) + redis (>= 4.2.0) + rufus-scheduler (~> 3.2) + sidekiq (>= 4, < 7) + tilt (>= 1.4.0) spring (4.2.1) sprockets (4.2.1) concurrent-ruby (~> 1.0) @@ -270,12 +289,16 @@ DEPENDENCIES jbuilder listen pg + pry pry-rails puma rails (~> 7.0.3) + redis rspec-rails sass-rails selenium-webdriver + sidekiq + sidekiq-scheduler (~> 4.0) spring turbolinks tzinfo-data diff --git a/app/models/news_detail.rb b/app/models/news_detail.rb new file mode 100644 index 00000000..b46fad00 --- /dev/null +++ b/app/models/news_detail.rb @@ -0,0 +1,6 @@ +class NewsDetail < ApplicationRecord + + scope :most_recent_story, -> {order(hn_id: :desc).limit(1).first} + + validates :hn_id, uniqueness: true +end \ No newline at end of file diff --git a/app/services/hacker_news/and_new_stories.rb b/app/services/hacker_news/and_new_stories.rb new file mode 100644 index 00000000..b3752e45 --- /dev/null +++ b/app/services/hacker_news/and_new_stories.rb @@ -0,0 +1,33 @@ +module HackerNews + class AddNewStories < Base + + + def call + + response = get_new_stories + + if response.class.name == 'Net::HTTPOK' + ## get news item details. + + story_ids = HackerNews::Base.new.get_new_stories + + story_ids = JSON.parse(response.body) + + story_ids.each do |story_id| + break if story_id < NewsDetail.most_recent_story.hn_id + HackerNews::CreateItemDetail.new(story_ids).call + + end + + else + ### do something on failure + end + + + end + + + + end + +end diff --git a/app/services/hacker_news/base.rb b/app/services/hacker_news/base.rb new file mode 100644 index 00000000..91e786cb --- /dev/null +++ b/app/services/hacker_news/base.rb @@ -0,0 +1,29 @@ +module HackerNews + class Base + + + def get_new_stories + url = URI.parse('https://hacker-news.firebaseio.com/v0/newstories.json') + + http = Net::HTTP.new(url.host, url.port) + http.use_ssl = (url.scheme == 'https') + + request = Net::HTTP::Get.new(url) + request['Content-Type'] = 'application/json' + + http.request(request) + + end + + + + def newest_story_id + + @_uri ||= begin + uri = URI('https://hacker-news.firebaseio.com/v0/maxitem.json') + Net::HTTP.get(uri).gsub(/\s+/, '').to_i + end + end + + end +end \ No newline at end of file diff --git a/app/services/hacker_news/create_item_detail.rb b/app/services/hacker_news/create_item_detail.rb new file mode 100644 index 00000000..c9b98244 --- /dev/null +++ b/app/services/hacker_news/create_item_detail.rb @@ -0,0 +1,43 @@ +module HackerNews + class CreateItemDetail < Base + + attr_reader :story_id + + def initialize(story_id) + @story_id = story_id + end + + def call + data = get_story_detail(story_id) + create_story_detail(data) + end + + + private + + def get_story_detail(story_id) + + url = URI.parse("https://hacker-news.firebaseio.com/v0/item/#{story_id}.json?") + http = Net::HTTP.new(url.host, url.port) + http.use_ssl = (url.scheme == 'https') + + request = Net::HTTP::Get.new(url) + request['Content-Type'] = 'application/json' + + http.request(request).body + + end + + def create_story_detail(data) + + data = JSON.parse(data) + @news_detail = NewsDetail.new(hn_id: data["id"], url: data["url"], + author: data["by"], score: data["score"], title: data["title"], + story_type: data["type"], comment_count: data["descendants"]) + + @news_detail.save! + end +0 + + end +end \ No newline at end of file diff --git a/app/sidekiq/poll_hacker_news_job.rb b/app/sidekiq/poll_hacker_news_job.rb new file mode 100644 index 00000000..9f325063 --- /dev/null +++ b/app/sidekiq/poll_hacker_news_job.rb @@ -0,0 +1,23 @@ + +class PollHackerNewsJob + include Sidekiq::Job + + def perform(*args) + if NewsDetail.count == 0 + + + + story_ids = HackerNews::Base.new.get_new_stories + + JSON.parse(story_ids.body).each do |story| + HackerNews::CreateItemDetail.new(story).call + end + end + + if NewsDetail.most_recent_story.hn_id < HackerNews::Base.new.newest_story_id + HackerNews.add_new_stories + end + + end + +end diff --git a/config/application.rb b/config/application.rb index dab4cec6..5763fbad 100644 --- a/config/application.rb +++ b/config/application.rb @@ -14,5 +14,7 @@ class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. + config.active_record.legacy_connection_handling = false + end end diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb new file mode 100644 index 00000000..8f3de0b4 --- /dev/null +++ b/config/initializers/sidekiq.rb @@ -0,0 +1,10 @@ +require 'sidekiq' +require 'sidekiq-scheduler' + + +Sidekiq.configure_server do |config| + config.on(:startup) do + Sidekiq.schedule = YAML.load_file(File.expand_path('../../sidekiq_scheduler.yml', __FILE__)) + SidekiqScheduler::Scheduler.instance.reload_schedule! + end +end \ No newline at end of file diff --git a/config/sidekiq_scheduler.yml b/config/sidekiq_scheduler.yml new file mode 100644 index 00000000..b6acc784 --- /dev/null +++ b/config/sidekiq_scheduler.yml @@ -0,0 +1,4 @@ +poll_hacker_news_job: + every: ['15m', first_in: '0s'] + class: PollHackerNewsJob + queue: default \ No newline at end of file diff --git a/db/migrate/20240812194904_create_news_details.rb b/db/migrate/20240812194904_create_news_details.rb new file mode 100644 index 00000000..cfdf4407 --- /dev/null +++ b/db/migrate/20240812194904_create_news_details.rb @@ -0,0 +1,14 @@ +class CreateNewsDetails < ActiveRecord::Migration[7.0] + def change + create_table :news_details do |t| + t.string :author # By in HN + t.integer :comment_count # Decendents in HN + t.integer :hn_id # HN id + t.string :url #HN url + t.integer :score #HN score + t.string :title #HN story title + t.string :story_type #HN story type + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index acc34f3b..3e927b1a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,10 +10,22 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2018_02_28_212101) do +ActiveRecord::Schema[7.0].define(version: 2024_08_12_194904) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" + create_table "news_details", force: :cascade do |t| + t.string "author" + t.integer "comment_count" + t.integer "hn_id" + t.string "url" + t.integer "score" + t.string "title" + t.string "story_type" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "users", force: :cascade do |t| t.string "first_name" t.string "last_name" diff --git a/spec/jobs/poll_hacker_news_job_spec.rb b/spec/jobs/poll_hacker_news_job_spec.rb new file mode 100644 index 00000000..f38f5c4f --- /dev/null +++ b/spec/jobs/poll_hacker_news_job_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe PollHackerNewsJob, type: :job do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/sidekiq/hard_job_spec.rb b/spec/sidekiq/hard_job_spec.rb new file mode 100644 index 00000000..b034fdee --- /dev/null +++ b/spec/sidekiq/hard_job_spec.rb @@ -0,0 +1,4 @@ +require 'rails_helper' +RSpec.describe HardJob, type: :job do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/sidekiq/poll_hacker_news_job_spec.rb b/spec/sidekiq/poll_hacker_news_job_spec.rb new file mode 100644 index 00000000..7dd34df7 --- /dev/null +++ b/spec/sidekiq/poll_hacker_news_job_spec.rb @@ -0,0 +1,4 @@ +require 'rails_helper' +RSpec.describe PollHackerNewsJob, type: :job do + pending "add some examples to (or delete) #{__FILE__}" +end From 0cd1f682c2f5c5ff18cdc53c595cafa77c6554bd Mon Sep 17 00:00:00 2001 From: John Verdone Date: Tue, 13 Aug 2024 01:04:58 -0400 Subject: [PATCH 04/16] Users can log out, up vote or down vote articles. A separate page was set up to list liked stories. users names who like a story will list listed with each story --- app/controllers/news_details_controller.rb | 39 ++++++++++++++ app/controllers/pages_controller.rb | 8 +++ app/models/news_detail.rb | 2 + app/models/user.rb | 2 + app/views/news_details/_news_item.html.erb | 19 +++++++ app/views/news_details/index.html.erb | 12 +++++ app/views/news_details/liked_index.html.erb | 11 ++++ config/environments/development.rb | 2 + config/initializers/devise.rb | 52 +++++++++++++++---- config/locales/devise.en.yml | 5 +- config/routes.rb | 13 +++++ ...0240813041304_create_user_liked_stories.rb | 9 ++++ db/schema.rb | 11 +++- 13 files changed, 173 insertions(+), 12 deletions(-) create mode 100644 app/controllers/news_details_controller.rb create mode 100644 app/views/news_details/_news_item.html.erb create mode 100644 app/views/news_details/index.html.erb create mode 100644 app/views/news_details/liked_index.html.erb create mode 100644 db/migrate/20240813041304_create_user_liked_stories.rb diff --git a/app/controllers/news_details_controller.rb b/app/controllers/news_details_controller.rb new file mode 100644 index 00000000..8e45b580 --- /dev/null +++ b/app/controllers/news_details_controller.rb @@ -0,0 +1,39 @@ +class NewsDetailsController < ApplicationController + before_action :authenticate_user! + def index + @news_details = NewsDetail.all + end + + def liked_index + @news_details = NewsDetail.joins(:users).distinct + end + + def upvote + @news_detail = NewsDetail.find(params[:id]) + @news_detail.users << current_user + + respond_to do |format| + format.html { redirect_to news_details_path } + end + end + + def downvote + @news_detail = NewsDetail.find(params[:id]) + @news_detail.users.delete(current_user) + + respond_to do |format| + format.html { redirect_to news_details_path } + end + end + + +end + +# id: 507, +# author: "el_benhameen", +# comment_count: 1, +# hn_id: 41231944, +# url: "https://www.nytimes.com/2024/08/12/health/alcohol-cancer-heart-disease.html", +# score: 1, +# title: "Older Adults Do Not Benefit from Moderate Drinking, Large Study Finds", +# story_type: "story", \ No newline at end of file diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index ce3bf586..fa65d144 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -1,2 +1,10 @@ class PagesController < ApplicationController + + + def index + ### top hacker news stories + end + + + end diff --git a/app/models/news_detail.rb b/app/models/news_detail.rb index b46fad00..1442baf2 100644 --- a/app/models/news_detail.rb +++ b/app/models/news_detail.rb @@ -3,4 +3,6 @@ class NewsDetail < ApplicationRecord scope :most_recent_story, -> {order(hn_id: :desc).limit(1).first} validates :hn_id, uniqueness: true + + has_and_belongs_to_many :users end \ No newline at end of file diff --git a/app/models/user.rb b/app/models/user.rb index b2091f9a..6e6c299e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,4 +3,6 @@ class User < ApplicationRecord # :confirmable, :lockable, :timeoutable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable + + has_and_belongs_to_many :news_details end diff --git a/app/views/news_details/_news_item.html.erb b/app/views/news_details/_news_item.html.erb new file mode 100644 index 00000000..733d112f --- /dev/null +++ b/app/views/news_details/_news_item.html.erb @@ -0,0 +1,19 @@ +
  • + + <%= news_detail.title %> + <%= link_to 'Article', news_detail.url %> +

    Liked by: + <%= news_detail.users.pluck(:first_name).join(', ') %> +

    + + +<%= button_to 'Upvote', upvote_news_detail_path(news_detail, status: 'updated'), method: :patch, remote: true, class: 'update-button' %> +<%= button_to 'Downvote', downvote_news_detail_path(news_detail, status: 'updated'), method: :patch, remote: true, class: 'update-button' %> + + + +
  • + + + + \ No newline at end of file diff --git a/app/views/news_details/index.html.erb b/app/views/news_details/index.html.erb new file mode 100644 index 00000000..7c070066 --- /dev/null +++ b/app/views/news_details/index.html.erb @@ -0,0 +1,12 @@ +

    Recent Top Stories

    +<%= link_to "Log out", destroy_user_session_path, method: :delete, class: "btn btn-danger" %> + +<%= link_to "Liked Stories", liked_index_news_details_path %> + + +
      + <% @news_details.each do |news_detail| %> + <%= render partial: "news_item", locals: {news_detail: news_detail} %> + <% end %> +
    + diff --git a/app/views/news_details/liked_index.html.erb b/app/views/news_details/liked_index.html.erb new file mode 100644 index 00000000..66527728 --- /dev/null +++ b/app/views/news_details/liked_index.html.erb @@ -0,0 +1,11 @@ +

    Liked Top Stories

    +<%= link_to "Log out", destroy_user_session_path, method: :delete, class: "btn btn-danger" %> + +<%= link_to "Recent Top Stories", news_details_path %> + +
      + <% @news_details.each do |news_detail| %> + <%= render partial: "news_item", locals: {news_detail: news_detail} %> + <% end %> +
    + diff --git a/config/environments/development.rb b/config/environments/development.rb index 5187e221..e43a9f50 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -51,4 +51,6 @@ # Use an evented file watcher to asynchronously detect changes in source code, # routes, locales, etc. This feature depends on the listen gem. config.file_watcher = ActiveSupport::EventedFileUpdateChecker + + end diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 962d4a7c..4cd56307 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -1,5 +1,11 @@ # frozen_string_literal: true +# Assuming you have not yet modified this file, each configuration option below +# is set to its default value. Note that some are commented out while others +# are not: uncommented lines are intended to protect your configuration from +# breaking changes in upgrades (i.e., in the event that future versions of +# Devise change the default values for those options). +# # Use this hook to configure devise mailer, warden hooks and so forth. # Many of these configuration options can be set straight in your model. Devise.setup do |config| @@ -8,7 +14,11 @@ # confirmation, reset password and unlock tokens in the database. # Devise will use the `secret_key_base` as its `secret_key` # by default. You can change it below and use your own secret key. - # config.secret_key = '3d8fdc791713e92d72d135adbaa58657b3661394b046a293632d59b4cf4ba76fc5369d8f67202bce93a62fc0aacf24878bcd5f7879d859b588919783efcf7eb3' + # config.secret_key = 'ff6ef85093968d28e61e663f250fee4c2be20c55e38d30f168b726002d04681a0fe9545755e26484a4d8e4feae1bf613d9b5d770ee7b8568305930302cc3fc3e' + + # ==> Controller configuration + # Configure the parent class to the devise controllers. + # config.parent_controller = 'DeviseController' # ==> Mailer Configuration # Configure the e-mail address which will be shown in Devise::Mailer, @@ -64,7 +74,10 @@ # Tell if authentication through HTTP Auth is enabled. False by default. # It can be set to an array that will enable http authentication only for the # given strategies, for example, `config.http_authenticatable = [:database]` will - # enable it only for database authentication. The supported strategies are: + # enable it only for database authentication. + # For API-only applications to support authentication "out-of-the-box", you will likely want to + # enable this with :database unless you are using a custom strategy. + # The supported strategies are: # :database = Support basic authentication with authentication key + password # config.http_authenticatable = false @@ -99,18 +112,21 @@ # config.reload_routes = true # ==> Configuration for :database_authenticatable - # For bcrypt, this is the cost for hashing the password and defaults to 11. If + # For bcrypt, this is the cost for hashing the password and defaults to 12. If # using other algorithms, it sets how many times you want the password to be hashed. + # The number of stretches used for generating the hashed password are stored + # with the hashed password. This allows you to change the stretches without + # invalidating existing passwords. # # Limiting the stretches to just one in testing will increase the performance of # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use # a value less than 10 in other environments. Note that, for bcrypt (the default # algorithm), the cost increases exponentially with the number of stretches (e.g. # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation). - config.stretches = Rails.env.test? ? 1 : 11 + config.stretches = Rails.env.test? ? 1 : 12 # Set up a pepper to generate the hashed password. - # config.pepper = '98f368775fc8e418915aa4d2185d5659bda9b2a2aae35a6bb5c2863536c1c7e1ff8884578d43324639ae4d9bc4c851a7c71739103378841fd7f8f9e0db32daea' + # config.pepper = '87001eb32fbe9f99917b7de4e80686792725077b33fd5c5bffd960ff88ad7082df369cc6626fd9e19c86d4be23a9173a74c7731f63158c317addfb3f7ae0f621' # Send a notification to the original email when the user's email is changed. # config.send_email_changed_notification = false @@ -122,8 +138,11 @@ # A period that the user is allowed to access the website even without # confirming their account. For instance, if set to 2.days, the user will be # able to access the website for two days without confirming their account, - # access will be blocked just in the third day. Default is 0.days, meaning - # the user cannot access the website without confirming their account. + # access will be blocked just in the third day. + # You can also set it to nil, which will allow the user to access the website + # without confirming their account. + # Default is 0.days, meaning the user cannot access the website without + # confirming their account. # config.allow_unconfirmed_access_for = 2.days # A period that the user is allowed to confirm their account before their @@ -237,14 +256,14 @@ # ==> Navigation configuration # Lists the formats that should be treated as navigational. Formats like - # :html, should redirect to the sign in page when the user does not have + # :html should redirect to the sign in page when the user does not have # access, but formats like :xml or :json, should return 401. # # If you have any extra navigational formats, like :iphone or :mobile, you # should add them to the navigational formats lists. # # The "*/*" below is required to match Internet Explorer requests. - # config.navigational_formats = ['*/*', :html] + # config.navigational_formats = ['*/*', :html, :turbo_stream] # The default HTTP method used to sign out a resource. Default is :delete. config.sign_out_via = :delete @@ -276,4 +295,19 @@ # When using OmniAuth, Devise cannot automatically set OmniAuth path, # so you need to do it manually. For the users scope, it would be: # config.omniauth_path_prefix = '/my_engine/users/auth' + + # ==> Hotwire/Turbo configuration + # When using Devise with Hotwire/Turbo, the http status for error responses + # and some redirects must match the following. The default in Devise for existing + # apps is `200 OK` and `302 Found` respectively, but new apps are generated with + # these new defaults that match Hotwire/Turbo behavior. + # Note: These might become the new default in future versions of Devise. + config.responder.error_status = :unprocessable_entity + config.responder.redirect_status = :see_other + + # ==> Configuration for :registerable + + # When set to false, does not sign a user in automatically after their password is + # changed. Defaults to true, so a user is signed in automatically after changing a password. + # config.sign_in_after_change_password = true end diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml index 0b8f1302..260e1c4b 100644 --- a/config/locales/devise.en.yml +++ b/config/locales/devise.en.yml @@ -1,4 +1,4 @@ -# Additional translations at https://github.com/plataformatec/devise/wiki/I18n +# Additional translations at https://github.com/heartcombo/devise/wiki/I18n en: devise: @@ -42,8 +42,9 @@ en: signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." - update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address." + update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirmation link to confirm your new email address." updated: "Your account has been updated successfully." + updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again." sessions: signed_in: "Signed in successfully." signed_out: "Signed out successfully." diff --git a/config/routes.rb b/config/routes.rb index c12ef082..ecb50634 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,17 @@ Rails.application.routes.draw do devise_for :users root to: 'pages#home' + + resources :news_details do + collection do + get :liked_index + end + member do + patch :upvote + patch :downvote + + end + end + + end diff --git a/db/migrate/20240813041304_create_user_liked_stories.rb b/db/migrate/20240813041304_create_user_liked_stories.rb new file mode 100644 index 00000000..8ec8652d --- /dev/null +++ b/db/migrate/20240813041304_create_user_liked_stories.rb @@ -0,0 +1,9 @@ +class CreateUserLikedStories < ActiveRecord::Migration[7.0] + def change + create_join_table :users, :news_details do |t| + t.index :user_id + t.index :news_detail_id + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 3e927b1a..4e9d6e2e 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2024_08_12_194904) do +ActiveRecord::Schema[7.0].define(version: 2024_08_13_041304) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -26,6 +26,15 @@ t.datetime "updated_at", null: false end + create_table "news_details_users", id: false, force: :cascade do |t| + t.bigint "user_id", null: false + t.bigint "news_detail_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["news_detail_id"], name: "index_news_details_users_on_news_detail_id" + t.index ["user_id"], name: "index_news_details_users_on_user_id" + end + create_table "users", force: :cascade do |t| t.string "first_name" t.string "last_name" From f218b729c150ff0f4e34a93cb54075434792d19f Mon Sep 17 00:00:00 2001 From: John Verdone Date: Tue, 13 Aug 2024 01:52:29 -0400 Subject: [PATCH 05/16] fix typo --- .../{and_new_stories.rb => add_new_stories.rb} | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) rename app/services/hacker_news/{and_new_stories.rb => add_new_stories.rb} (65%) diff --git a/app/services/hacker_news/and_new_stories.rb b/app/services/hacker_news/add_new_stories.rb similarity index 65% rename from app/services/hacker_news/and_new_stories.rb rename to app/services/hacker_news/add_new_stories.rb index b3752e45..a8c9bf2d 100644 --- a/app/services/hacker_news/and_new_stories.rb +++ b/app/services/hacker_news/add_new_stories.rb @@ -3,19 +3,18 @@ class AddNewStories < Base def call - response = get_new_stories if response.class.name == 'Net::HTTPOK' ## get news item details. - story_ids = HackerNews::Base.new.get_new_stories + story_ids = get_new_stories story_ids = JSON.parse(response.body) - + most_recent_id = NewsDetail.most_recent_story.hn_id story_ids.each do |story_id| - break if story_id < NewsDetail.most_recent_story.hn_id - HackerNews::CreateItemDetail.new(story_ids).call + break if story_id <= most_recent_id + HackerNews::CreateItemDetail.new(story_id).call end @@ -31,3 +30,5 @@ def call end end + + From d348ecee24b9c25ed4dc096d4baa0416be46a6d2 Mon Sep 17 00:00:00 2001 From: John Verdone Date: Tue, 13 Aug 2024 01:52:39 -0400 Subject: [PATCH 06/16] fix typo --- app/sidekiq/poll_hacker_news_job.rb | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/sidekiq/poll_hacker_news_job.rb b/app/sidekiq/poll_hacker_news_job.rb index 9f325063..937293df 100644 --- a/app/sidekiq/poll_hacker_news_job.rb +++ b/app/sidekiq/poll_hacker_news_job.rb @@ -14,8 +14,9 @@ def perform(*args) end end - if NewsDetail.most_recent_story.hn_id < HackerNews::Base.new.newest_story_id - HackerNews.add_new_stories + if NewsDetail.most_recent_story.hn_id < HackerNews::Base.new.newest_story_id + puts "adding new story" + HackerNews::AddNewStories.new.call end end From 40429f6bd0febc86cf0cd512900c6dd8a66dce34 Mon Sep 17 00:00:00 2001 From: John Verdone Date: Tue, 13 Aug 2024 01:52:55 -0400 Subject: [PATCH 07/16] added foreman and procfile --- Gemfile | 2 ++ Gemfile.lock | 2 ++ Procfile | 2 ++ 3 files changed, 6 insertions(+) create mode 100644 Procfile diff --git a/Gemfile b/Gemfile index 766fca96..5e0e7f28 100644 --- a/Gemfile +++ b/Gemfile @@ -21,6 +21,8 @@ gem 'redis' group :development do + gem 'foreman', group: :development + gem 'spring' gem 'web-console' gem 'listen' diff --git a/Gemfile.lock b/Gemfile.lock index f9ea4334..ba8847a5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -106,6 +106,7 @@ GEM tzinfo execjs (2.9.1) ffi (1.17.0-x86_64-darwin) + foreman (0.88.1) fugit (1.11.0) et-orbi (~> 1, >= 1.2.11) raabro (~> 1.4) @@ -286,6 +287,7 @@ DEPENDENCIES capybara coffee-rails devise + foreman jbuilder listen pg diff --git a/Procfile b/Procfile new file mode 100644 index 00000000..f75718f1 --- /dev/null +++ b/Procfile @@ -0,0 +1,2 @@ +web: bin/rails s +worker: bundle exec sidekiq \ No newline at end of file From db268784a58d68dafb8cadf3aac58caa4107ea0a Mon Sep 17 00:00:00 2001 From: John Verdone Date: Tue, 13 Aug 2024 07:11:50 -0400 Subject: [PATCH 08/16] remove unused job file --- spec/sidekiq/hard_job_spec.rb | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 spec/sidekiq/hard_job_spec.rb diff --git a/spec/sidekiq/hard_job_spec.rb b/spec/sidekiq/hard_job_spec.rb deleted file mode 100644 index b034fdee..00000000 --- a/spec/sidekiq/hard_job_spec.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'rails_helper' -RSpec.describe HardJob, type: :job do - pending "add some examples to (or delete) #{__FILE__}" -end From 7c275dd2966127825d1a2adcd9cd5603775a657a Mon Sep 17 00:00:00 2001 From: John Verdone Date: Tue, 13 Aug 2024 07:12:51 -0400 Subject: [PATCH 09/16] added pagination and updated procfile --- Gemfile | 1 + Gemfile.lock | 13 +++++++++++++ Procfile | 2 +- app/controllers/news_details_controller.rb | 4 ++-- app/services/hacker_news/create_item_detail.rb | 4 +--- app/sidekiq/poll_hacker_news_job.rb | 10 +++++----- app/views/news_details/index.html.erb | 7 +++++-- 7 files changed, 28 insertions(+), 13 deletions(-) diff --git a/Gemfile b/Gemfile index 5e0e7f28..897c9314 100644 --- a/Gemfile +++ b/Gemfile @@ -17,6 +17,7 @@ gem 'uglifier' gem 'sidekiq' gem 'sidekiq-scheduler', '~> 4.0' gem 'redis' +gem 'kaminari' diff --git a/Gemfile.lock b/Gemfile.lock index ba8847a5..5a36ee4c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -117,6 +117,18 @@ GEM jbuilder (2.12.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) + kaminari (1.2.2) + activesupport (>= 4.1.0) + kaminari-actionview (= 1.2.2) + kaminari-activerecord (= 1.2.2) + kaminari-core (= 1.2.2) + kaminari-actionview (1.2.2) + actionview + kaminari-core (= 1.2.2) + kaminari-activerecord (1.2.2) + activerecord + kaminari-core (= 1.2.2) + kaminari-core (1.2.2) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -289,6 +301,7 @@ DEPENDENCIES devise foreman jbuilder + kaminari listen pg pry diff --git a/Procfile b/Procfile index f75718f1..e84acd74 100644 --- a/Procfile +++ b/Procfile @@ -1,2 +1,2 @@ -web: bin/rails s +web: bin/rails server -p 3000 worker: bundle exec sidekiq \ No newline at end of file diff --git a/app/controllers/news_details_controller.rb b/app/controllers/news_details_controller.rb index 8e45b580..e86cb357 100644 --- a/app/controllers/news_details_controller.rb +++ b/app/controllers/news_details_controller.rb @@ -1,11 +1,11 @@ class NewsDetailsController < ApplicationController before_action :authenticate_user! def index - @news_details = NewsDetail.all + @news_details = NewsDetail.includes(:users).page(params[:page]) end def liked_index - @news_details = NewsDetail.joins(:users).distinct + @news_details = NewsDetail.joins(:users).distinct.page(params[:page]) end def upvote diff --git a/app/services/hacker_news/create_item_detail.rb b/app/services/hacker_news/create_item_detail.rb index c9b98244..6871f174 100644 --- a/app/services/hacker_news/create_item_detail.rb +++ b/app/services/hacker_news/create_item_detail.rb @@ -35,9 +35,7 @@ def create_story_detail(data) author: data["by"], score: data["score"], title: data["title"], story_type: data["type"], comment_count: data["descendants"]) - @news_detail.save! + @news_detail.save end -0 - end end \ No newline at end of file diff --git a/app/sidekiq/poll_hacker_news_job.rb b/app/sidekiq/poll_hacker_news_job.rb index 937293df..80dcbe11 100644 --- a/app/sidekiq/poll_hacker_news_job.rb +++ b/app/sidekiq/poll_hacker_news_job.rb @@ -3,20 +3,20 @@ class PollHackerNewsJob include Sidekiq::Job def perform(*args) + puts 'polling Hacker News' + ## If no news deatilas exist create intial set of them if NewsDetail.count == 0 - - - story_ids = HackerNews::Base.new.get_new_stories - JSON.parse(story_ids.body).each do |story| HackerNews::CreateItemDetail.new(story).call end end - if NewsDetail.most_recent_story.hn_id < HackerNews::Base.new.newest_story_id + if HackerNews::Base.new.newest_story_id < HackerNews::Base.new.newest_story_id puts "adding new story" HackerNews::AddNewStories.new.call + else + puts 'No new stories' end end diff --git a/app/views/news_details/index.html.erb b/app/views/news_details/index.html.erb index 7c070066..82c939a3 100644 --- a/app/views/news_details/index.html.erb +++ b/app/views/news_details/index.html.erb @@ -1,8 +1,9 @@

    Recent Top Stories

    -<%= link_to "Log out", destroy_user_session_path, method: :delete, class: "btn btn-danger" %> -<%= link_to "Liked Stories", liked_index_news_details_path %> +<%= paginate @news_details %> +<%= link_to "Log out", destroy_user_session_path, method: :delete, class: "btn btn-danger" %> +<%= link_to "Liked Stories", liked_index_news_details_path %>
      <% @news_details.each do |news_detail| %> @@ -10,3 +11,5 @@ <% end %>
    +<%= paginate @news_details %> + From 481b38f8f34c7d19db8fab1209f0cb2960a50f36 Mon Sep 17 00:00:00 2001 From: John Verdone Date: Tue, 13 Aug 2024 07:25:27 -0400 Subject: [PATCH 10/16] update routes --- config/routes.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index ecb50634..3262718a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,8 +1,8 @@ Rails.application.routes.draw do - devise_for :users - root to: 'pages#home' + devise_for :users, only: [:sessions] + root to: 'news_details#index' - resources :news_details do + resources :news_details, only: [:index] do collection do get :liked_index end From 2985270681b9da9ecbd8a7434f38c7ef4e2864af Mon Sep 17 00:00:00 2001 From: John Verdone Date: Tue, 13 Aug 2024 07:25:46 -0400 Subject: [PATCH 11/16] remove uneeded devise files --- app/views/devise/confirmations/new.html.erb | 16 ------- .../mailer/confirmation_instructions.html.erb | 5 --- .../devise/mailer/email_changed.html.erb | 7 --- .../devise/mailer/password_change.html.erb | 3 -- .../reset_password_instructions.html.erb | 8 ---- .../mailer/unlock_instructions.html.erb | 7 --- app/views/devise/passwords/edit.html.erb | 25 ----------- app/views/devise/passwords/new.html.erb | 16 ------- app/views/devise/registrations/edit.html.erb | 43 ------------------- app/views/devise/registrations/new.html.erb | 29 ------------- app/views/devise/sessions/new.html.erb | 9 ---- 11 files changed, 168 deletions(-) delete mode 100644 app/views/devise/confirmations/new.html.erb delete mode 100644 app/views/devise/mailer/confirmation_instructions.html.erb delete mode 100644 app/views/devise/mailer/email_changed.html.erb delete mode 100644 app/views/devise/mailer/password_change.html.erb delete mode 100644 app/views/devise/mailer/reset_password_instructions.html.erb delete mode 100644 app/views/devise/mailer/unlock_instructions.html.erb delete mode 100644 app/views/devise/passwords/edit.html.erb delete mode 100644 app/views/devise/passwords/new.html.erb delete mode 100644 app/views/devise/registrations/edit.html.erb delete mode 100644 app/views/devise/registrations/new.html.erb diff --git a/app/views/devise/confirmations/new.html.erb b/app/views/devise/confirmations/new.html.erb deleted file mode 100644 index b12dd0cb..00000000 --- a/app/views/devise/confirmations/new.html.erb +++ /dev/null @@ -1,16 +0,0 @@ -

    Resend confirmation instructions

    - -<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %> - <%= render "devise/shared/error_messages", resource: resource %> - -
    - <%= f.label :email %>
    - <%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %> -
    - -
    - <%= f.submit "Resend confirmation instructions" %> -
    -<% end %> - -<%= render "devise/shared/links" %> diff --git a/app/views/devise/mailer/confirmation_instructions.html.erb b/app/views/devise/mailer/confirmation_instructions.html.erb deleted file mode 100644 index dc55f64f..00000000 --- a/app/views/devise/mailer/confirmation_instructions.html.erb +++ /dev/null @@ -1,5 +0,0 @@ -

    Welcome <%= @email %>!

    - -

    You can confirm your account email through the link below:

    - -

    <%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>

    diff --git a/app/views/devise/mailer/email_changed.html.erb b/app/views/devise/mailer/email_changed.html.erb deleted file mode 100644 index 32f4ba80..00000000 --- a/app/views/devise/mailer/email_changed.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -

    Hello <%= @email %>!

    - -<% if @resource.try(:unconfirmed_email?) %> -

    We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.

    -<% else %> -

    We're contacting you to notify you that your email has been changed to <%= @resource.email %>.

    -<% end %> diff --git a/app/views/devise/mailer/password_change.html.erb b/app/views/devise/mailer/password_change.html.erb deleted file mode 100644 index b41daf47..00000000 --- a/app/views/devise/mailer/password_change.html.erb +++ /dev/null @@ -1,3 +0,0 @@ -

    Hello <%= @resource.email %>!

    - -

    We're contacting you to notify you that your password has been changed.

    diff --git a/app/views/devise/mailer/reset_password_instructions.html.erb b/app/views/devise/mailer/reset_password_instructions.html.erb deleted file mode 100644 index f667dc12..00000000 --- a/app/views/devise/mailer/reset_password_instructions.html.erb +++ /dev/null @@ -1,8 +0,0 @@ -

    Hello <%= @resource.email %>!

    - -

    Someone has requested a link to change your password. You can do this through the link below.

    - -

    <%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>

    - -

    If you didn't request this, please ignore this email.

    -

    Your password won't change until you access the link above and create a new one.

    diff --git a/app/views/devise/mailer/unlock_instructions.html.erb b/app/views/devise/mailer/unlock_instructions.html.erb deleted file mode 100644 index 41e148bf..00000000 --- a/app/views/devise/mailer/unlock_instructions.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -

    Hello <%= @resource.email %>!

    - -

    Your account has been locked due to an excessive number of unsuccessful sign in attempts.

    - -

    Click the link below to unlock your account:

    - -

    <%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>

    diff --git a/app/views/devise/passwords/edit.html.erb b/app/views/devise/passwords/edit.html.erb deleted file mode 100644 index 5fbb9ff0..00000000 --- a/app/views/devise/passwords/edit.html.erb +++ /dev/null @@ -1,25 +0,0 @@ -

    Change your password

    - -<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> - <%= render "devise/shared/error_messages", resource: resource %> - <%= f.hidden_field :reset_password_token %> - -
    - <%= f.label :password, "New password" %>
    - <% if @minimum_password_length %> - (<%= @minimum_password_length %> characters minimum)
    - <% end %> - <%= f.password_field :password, autofocus: true, autocomplete: "new-password" %> -
    - -
    - <%= f.label :password_confirmation, "Confirm new password" %>
    - <%= f.password_field :password_confirmation, autocomplete: "new-password" %> -
    - -
    - <%= f.submit "Change my password" %> -
    -<% end %> - -<%= render "devise/shared/links" %> diff --git a/app/views/devise/passwords/new.html.erb b/app/views/devise/passwords/new.html.erb deleted file mode 100644 index 9b486b81..00000000 --- a/app/views/devise/passwords/new.html.erb +++ /dev/null @@ -1,16 +0,0 @@ -

    Forgot your password?

    - -<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %> - <%= render "devise/shared/error_messages", resource: resource %> - -
    - <%= f.label :email %>
    - <%= f.email_field :email, autofocus: true, autocomplete: "email" %> -
    - -
    - <%= f.submit "Send me reset password instructions" %> -
    -<% end %> - -<%= render "devise/shared/links" %> diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb deleted file mode 100644 index b82e3365..00000000 --- a/app/views/devise/registrations/edit.html.erb +++ /dev/null @@ -1,43 +0,0 @@ -

    Edit <%= resource_name.to_s.humanize %>

    - -<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> - <%= render "devise/shared/error_messages", resource: resource %> - -
    - <%= f.label :email %>
    - <%= f.email_field :email, autofocus: true, autocomplete: "email" %> -
    - - <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> -
    Currently waiting confirmation for: <%= resource.unconfirmed_email %>
    - <% end %> - -
    - <%= f.label :password %> (leave blank if you don't want to change it)
    - <%= f.password_field :password, autocomplete: "new-password" %> - <% if @minimum_password_length %> -
    - <%= @minimum_password_length %> characters minimum - <% end %> -
    - -
    - <%= f.label :password_confirmation %>
    - <%= f.password_field :password_confirmation, autocomplete: "new-password" %> -
    - -
    - <%= f.label :current_password %> (we need your current password to confirm your changes)
    - <%= f.password_field :current_password, autocomplete: "current-password" %> -
    - -
    - <%= f.submit "Update" %> -
    -<% end %> - -

    Cancel my account

    - -
    Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %>
    - -<%= link_to "Back", :back %> diff --git a/app/views/devise/registrations/new.html.erb b/app/views/devise/registrations/new.html.erb deleted file mode 100644 index d655b66f..00000000 --- a/app/views/devise/registrations/new.html.erb +++ /dev/null @@ -1,29 +0,0 @@ -

    Sign up

    - -<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> - <%= render "devise/shared/error_messages", resource: resource %> - -
    - <%= f.label :email %>
    - <%= f.email_field :email, autofocus: true, autocomplete: "email" %> -
    - -
    - <%= f.label :password %> - <% if @minimum_password_length %> - (<%= @minimum_password_length %> characters minimum) - <% end %>
    - <%= f.password_field :password, autocomplete: "new-password" %> -
    - -
    - <%= f.label :password_confirmation %>
    - <%= f.password_field :password_confirmation, autocomplete: "new-password" %> -
    - -
    - <%= f.submit "Sign up" %> -
    -<% end %> - -<%= render "devise/shared/links" %> diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 5ede9648..819ae5b8 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -11,16 +11,7 @@ <%= f.password_field :password, autocomplete: "current-password" %> - <% if devise_mapping.rememberable? %> -
    - <%= f.check_box :remember_me %> - <%= f.label :remember_me %> -
    - <% end %> -
    <%= f.submit "Log in" %>
    <% end %> - -<%= render "devise/shared/links" %> From f84947f28132d24fb36646a83ed295cc871b15f6 Mon Sep 17 00:00:00 2001 From: John Verdone Date: Tue, 13 Aug 2024 10:51:11 -0400 Subject: [PATCH 12/16] clean up and testing --- app/services/hacker_news/add_new_stories.rb | 41 +++++++------------ app/services/hacker_news/base.rb | 1 + .../hacker_news/create_item_detail.rb | 22 +++++++--- app/services/hacker_news/get_story_ids.rb | 18 ++++++++ app/sidekiq/poll_hacker_news_job.rb | 19 ++++++--- config/environments/test.rb | 2 +- config/sidekiq_scheduler.yml | 2 +- spec/jobs/poll_hacker_news_job_spec.rb | 5 --- spec/rails_helper.rb | 4 ++ .../hacker_news/add_new_stories_spec.rb | 33 +++++++++++++++ spec/services/hacker_news/base_spec.rb | 0 .../hacker_news/create_item_details_spec.rb | 29 +++++++++++++ .../hacker_news/get_story_ids_spec.rb | 23 +++++++++++ spec/sidekiq/poll_hacker_news_job_spec.rb | 20 ++++++++- 14 files changed, 173 insertions(+), 46 deletions(-) create mode 100644 app/services/hacker_news/get_story_ids.rb delete mode 100644 spec/jobs/poll_hacker_news_job_spec.rb create mode 100644 spec/services/hacker_news/add_new_stories_spec.rb create mode 100644 spec/services/hacker_news/base_spec.rb create mode 100644 spec/services/hacker_news/create_item_details_spec.rb create mode 100644 spec/services/hacker_news/get_story_ids_spec.rb diff --git a/app/services/hacker_news/add_new_stories.rb b/app/services/hacker_news/add_new_stories.rb index a8c9bf2d..37c69c5c 100644 --- a/app/services/hacker_news/add_new_stories.rb +++ b/app/services/hacker_news/add_new_stories.rb @@ -1,34 +1,23 @@ module HackerNews class AddNewStories < Base + attr_reader :story_ids - def call - response = get_new_stories - - if response.class.name == 'Net::HTTPOK' - ## get news item details. - - story_ids = get_new_stories - - story_ids = JSON.parse(response.body) - most_recent_id = NewsDetail.most_recent_story.hn_id - story_ids.each do |story_id| - break if story_id <= most_recent_id - HackerNews::CreateItemDetail.new(story_id).call - - end - - else - ### do something on failure - end + def initialize(story_ids) + @story_ids = story_ids + end + def call + + story_ids.each do |story_id| + next if NewsDetail.find_by(hn_id: story_id) + + @result = HackerNews::CreateItemDetail.new(story_id).call + break if !@result.success? + end + + @result || Result.new(false, nil, "No new stories added") end - - - end - -end - - +end \ No newline at end of file diff --git a/app/services/hacker_news/base.rb b/app/services/hacker_news/base.rb index 91e786cb..1758b899 100644 --- a/app/services/hacker_news/base.rb +++ b/app/services/hacker_news/base.rb @@ -1,5 +1,6 @@ module HackerNews class Base + Result = Struct.new(:success?, :data, :errors) def get_new_stories diff --git a/app/services/hacker_news/create_item_detail.rb b/app/services/hacker_news/create_item_detail.rb index 6871f174..34282b3f 100644 --- a/app/services/hacker_news/create_item_detail.rb +++ b/app/services/hacker_news/create_item_detail.rb @@ -30,12 +30,24 @@ def get_story_detail(story_id) def create_story_detail(data) + data = JSON.parse(data) - @news_detail = NewsDetail.new(hn_id: data["id"], url: data["url"], - author: data["by"], score: data["score"], title: data["title"], - story_type: data["type"], comment_count: data["descendants"]) - - @news_detail.save + if data.present? + @news_detail = NewsDetail.new(hn_id: data["id"], url: data["url"], + author: data["by"], score: data["score"], title: data["title"], + story_type: data["type"], comment_count: data["descendants"]) + + if @news_detail.save + Result.new(true, nil, "") + else + Result.new(false, data["hn_id"], 'failed saving HN details') + end + else + Result.new(false, nil, 'failed saving HN details') + end + + + end end end \ No newline at end of file diff --git a/app/services/hacker_news/get_story_ids.rb b/app/services/hacker_news/get_story_ids.rb new file mode 100644 index 00000000..0825d94e --- /dev/null +++ b/app/services/hacker_news/get_story_ids.rb @@ -0,0 +1,18 @@ +module HackerNews + class GetStoryIds < Base + + def call + response = get_new_stories + + if response.class.name == 'Net::HTTPOK' + ## get news item details. + + story_ids = get_new_stories + story_ids = JSON.parse(response.body) + Result.new(true, story_ids ,'' ) + else + Result.new(false, nil, 'Request to HN failed') + end + end + end +end \ No newline at end of file diff --git a/app/sidekiq/poll_hacker_news_job.rb b/app/sidekiq/poll_hacker_news_job.rb index 80dcbe11..d40edea7 100644 --- a/app/sidekiq/poll_hacker_news_job.rb +++ b/app/sidekiq/poll_hacker_news_job.rb @@ -5,16 +5,23 @@ class PollHackerNewsJob def perform(*args) puts 'polling Hacker News' ## If no news deatilas exist create intial set of them + if NewsDetail.count == 0 - story_ids = HackerNews::Base.new.get_new_stories - JSON.parse(story_ids.body).each do |story| - HackerNews::CreateItemDetail.new(story).call + result = HackerNews::GetStoryIds.new.call + result.data.each do |story_id| + HackerNews::CreateItemDetail.new(story_id).call end end - - if HackerNews::Base.new.newest_story_id < HackerNews::Base.new.newest_story_id + most_recent_story = NewsDetail.most_recent_story.try(:hn_id) || 0 + if most_recent_story < HackerNews::Base.new.newest_story_id puts "adding new story" - HackerNews::AddNewStories.new.call + + story_id_result = HackerNews::GetStoryIds.new.call + + story_ids = story_id_result.data + result = HackerNews::AddNewStories.new(story_ids).call + + puts "#{result.success? ? ' New stories added' : result.errors}" else puts 'No new stories' end diff --git a/config/environments/test.rb b/config/environments/test.rb index 8e5cbde5..7b6dc4c0 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -5,7 +5,7 @@ # test suite. You never need to work with it otherwise. Remember that # your test database is "scratch space" for the test suite and is wiped # and recreated between test runs. Don't rely on the data there! - config.cache_classes = true + config.cache_classes = false # Do not eager load code on boot. This avoids loading your whole application # just for the purpose of running a single test. If you are using a tool that diff --git a/config/sidekiq_scheduler.yml b/config/sidekiq_scheduler.yml index b6acc784..a8da8fb4 100644 --- a/config/sidekiq_scheduler.yml +++ b/config/sidekiq_scheduler.yml @@ -1,4 +1,4 @@ poll_hacker_news_job: - every: ['15m', first_in: '0s'] + every: ['5m', first_in: '0s'] class: PollHackerNewsJob queue: default \ No newline at end of file diff --git a/spec/jobs/poll_hacker_news_job_spec.rb b/spec/jobs/poll_hacker_news_job_spec.rb deleted file mode 100644 index f38f5c4f..00000000 --- a/spec/jobs/poll_hacker_news_job_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'rails_helper' - -RSpec.describe PollHackerNewsJob, type: :job do - pending "add some examples to (or delete) #{__FILE__}" -end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index bbe1ba57..b1131ddd 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -26,6 +26,8 @@ # If you are not using ActiveRecord, you can remove this line. ActiveRecord::Migration.maintain_test_schema! + + RSpec.configure do |config| # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" @@ -35,6 +37,8 @@ # instead of true. config.use_transactional_fixtures = true + + # RSpec Rails can automatically mix in different behaviours to your tests # based on their file location, for example enabling you to call `get` and # `post` in specs under `spec/controllers`. diff --git a/spec/services/hacker_news/add_new_stories_spec.rb b/spec/services/hacker_news/add_new_stories_spec.rb new file mode 100644 index 00000000..6771b7dd --- /dev/null +++ b/spec/services/hacker_news/add_new_stories_spec.rb @@ -0,0 +1,33 @@ +require 'rails_helper' + + +RSpec.describe HackerNews::AddNewStories do + subject(:service) { described_class} + + describe '#call' do + context 'when service is called' do + it 'adds new stories' do + result = service.new([41234588]).call + expect(result.success?).to be true + end + + it 'fails to add' do + result = service.new([99999999111]).call + expect(result.success?).to be false + end + end + + context 'does not add if story is already save in NewsDetail' do + it 'does not save' do + service.new([41229573, 41229555, 41235733, 41235723, 41235721]).call + + service.new([41229600, 41229597, 41229595, 41229589, 41229582, + 41229573, 41229555, 41235733, 41235723, 41235721]).call + + + expect(NewsDetail.count).to eq(10) + + end + end + end +end \ No newline at end of file diff --git a/spec/services/hacker_news/base_spec.rb b/spec/services/hacker_news/base_spec.rb new file mode 100644 index 00000000..e69de29b diff --git a/spec/services/hacker_news/create_item_details_spec.rb b/spec/services/hacker_news/create_item_details_spec.rb new file mode 100644 index 00000000..ce65714e --- /dev/null +++ b/spec/services/hacker_news/create_item_details_spec.rb @@ -0,0 +1,29 @@ +require 'rails_helper' + +RSpec.describe HackerNews::CreateItemDetail do + subject(:service) {described_class} + + + describe '#call' do + context 'creates new NewsDetail from HN story ID' do + + it 'saves new news detail' do + result = service.new(41234585).call + + expect(result.success?).to be true + end + + it 'does not save duplicates' do + service.new(41234585).call + result = service.new(41234585).call + expect(result.success?).to be false + end + + it 'does not save invalid data' do + result = service.new(4123458599999).call + expect(result.success?).to be false + end + end + + end +end \ No newline at end of file diff --git a/spec/services/hacker_news/get_story_ids_spec.rb b/spec/services/hacker_news/get_story_ids_spec.rb new file mode 100644 index 00000000..9337e0db --- /dev/null +++ b/spec/services/hacker_news/get_story_ids_spec.rb @@ -0,0 +1,23 @@ +require 'rails_helper' + + +RSpec.describe HackerNews::GetStoryIds do + subject(:service) { described_class.new } + + describe '#call' do + context 'when service is called' do + it 'gets storu ids' do + result = service.call + + expect(result.success?).to be true + + end + end + + + end + + + + +end \ No newline at end of file diff --git a/spec/sidekiq/poll_hacker_news_job_spec.rb b/spec/sidekiq/poll_hacker_news_job_spec.rb index 7dd34df7..0675ece1 100644 --- a/spec/sidekiq/poll_hacker_news_job_spec.rb +++ b/spec/sidekiq/poll_hacker_news_job_spec.rb @@ -1,4 +1,20 @@ require 'rails_helper' -RSpec.describe PollHackerNewsJob, type: :job do - pending "add some examples to (or delete) #{__FILE__}" +RSpec.describe PollHackerNewsJob do + subject(:service) { described_class} + + + let(:news_detail) { NewsDetail.create(hn_id: 1)} + describe '#perform' do + it 'intial perfrom populates db' do + + service.new.perform + expect(NewsDetail.count).to eq(500) + end + + it 'addtional performs will add to db' do + news_detail + service.new.perform + expect(NewsDetail.count).to eq(501) + end + end end From b33c0eb07ecb784e31a441163d9100bd2d13184e Mon Sep 17 00:00:00 2001 From: John Verdone Date: Tue, 13 Aug 2024 11:03:15 -0400 Subject: [PATCH 13/16] basic linting --- app/controllers/news_details_controller.rb | 15 ++-------- app/controllers/pages_controller.rb | 7 +---- app/models/news_detail.rb | 5 ++-- app/services/hacker_news/add_new_stories.rb | 19 +++++------- app/services/hacker_news/base.rb | 14 ++------- .../hacker_news/create_item_detail.rb | 29 +++++++------------ app/services/hacker_news/get_story_ids.rb | 9 +++--- app/sidekiq/poll_hacker_news_job.rb | 21 ++++++-------- app/views/news_details/index.html.erb | 2 +- app/views/news_details/liked_index.html.erb | 2 +- .../20180228212101_devise_create_users.rb | 5 ++-- .../20240812194904_create_news_details.rb | 12 ++++---- spec/models/user_spec.rb | 8 ++--- .../hacker_news/add_new_stories_spec.rb | 27 ++++++++--------- .../hacker_news/create_item_details_spec.rb | 15 ++++------ .../hacker_news/get_story_ids_spec.rb | 14 ++------- spec/sidekiq/poll_hacker_news_job_spec.rb | 14 ++++----- test/application_system_test_case.rb | 2 +- 18 files changed, 81 insertions(+), 139 deletions(-) diff --git a/app/controllers/news_details_controller.rb b/app/controllers/news_details_controller.rb index e86cb357..fc661c0a 100644 --- a/app/controllers/news_details_controller.rb +++ b/app/controllers/news_details_controller.rb @@ -13,7 +13,7 @@ def upvote @news_detail.users << current_user respond_to do |format| - format.html { redirect_to news_details_path } + format.html { redirect_to news_details_path } end end @@ -22,18 +22,7 @@ def downvote @news_detail.users.delete(current_user) respond_to do |format| - format.html { redirect_to news_details_path } + format.html { redirect_to news_details_path } end end - - end - -# id: 507, -# author: "el_benhameen", -# comment_count: 1, -# hn_id: 41231944, -# url: "https://www.nytimes.com/2024/08/12/health/alcohol-cancer-heart-disease.html", -# score: 1, -# title: "Older Adults Do Not Benefit from Moderate Drinking, Large Study Finds", -# story_type: "story", \ No newline at end of file diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index fa65d144..c2cef141 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -1,10 +1,5 @@ class PagesController < ApplicationController - - def index - ### top hacker news stories + ## not used end - - - end diff --git a/app/models/news_detail.rb b/app/models/news_detail.rb index 1442baf2..6a00b93b 100644 --- a/app/models/news_detail.rb +++ b/app/models/news_detail.rb @@ -1,8 +1,7 @@ class NewsDetail < ApplicationRecord - - scope :most_recent_story, -> {order(hn_id: :desc).limit(1).first} + scope :most_recent_story, -> { order(hn_id: :desc).limit(1).first } validates :hn_id, uniqueness: true has_and_belongs_to_many :users -end \ No newline at end of file +end diff --git a/app/services/hacker_news/add_new_stories.rb b/app/services/hacker_news/add_new_stories.rb index 37c69c5c..61f2ff74 100644 --- a/app/services/hacker_news/add_new_stories.rb +++ b/app/services/hacker_news/add_new_stories.rb @@ -1,6 +1,5 @@ module HackerNews class AddNewStories < Base - attr_reader :story_ids def initialize(story_ids) @@ -8,16 +7,14 @@ def initialize(story_ids) end def call - - story_ids.each do |story_id| - next if NewsDetail.find_by(hn_id: story_id) - - @result = HackerNews::CreateItemDetail.new(story_id).call - break if !@result.success? - end - - @result || Result.new(false, nil, "No new stories added") + next if NewsDetail.find_by(hn_id: story_id) + + @result = HackerNews::CreateItemDetail.new(story_id).call + break unless @result.success? + end + + @result || Result.new(false, nil, 'No new stories added') end end -end \ No newline at end of file +end diff --git a/app/services/hacker_news/base.rb b/app/services/hacker_news/base.rb index 1758b899..4535d6e8 100644 --- a/app/services/hacker_news/base.rb +++ b/app/services/hacker_news/base.rb @@ -2,29 +2,21 @@ module HackerNews class Base Result = Struct.new(:success?, :data, :errors) - def get_new_stories url = URI.parse('https://hacker-news.firebaseio.com/v0/newstories.json') http = Net::HTTP.new(url.host, url.port) http.use_ssl = (url.scheme == 'https') - request = Net::HTTP::Get.new(url) request['Content-Type'] = 'application/json' - http.request(request) - end - - def newest_story_id - @_uri ||= begin - uri = URI('https://hacker-news.firebaseio.com/v0/maxitem.json') - Net::HTTP.get(uri).gsub(/\s+/, '').to_i + uri = URI('https://hacker-news.firebaseio.com/v0/maxitem.json') + Net::HTTP.get(uri).gsub(/\s+/, '').to_i end end - end -end \ No newline at end of file +end diff --git a/app/services/hacker_news/create_item_detail.rb b/app/services/hacker_news/create_item_detail.rb index 34282b3f..d8fbdde5 100644 --- a/app/services/hacker_news/create_item_detail.rb +++ b/app/services/hacker_news/create_item_detail.rb @@ -1,53 +1,44 @@ module HackerNews class CreateItemDetail < Base - attr_reader :story_id def initialize(story_id) @story_id = story_id end - def call - data = get_story_detail(story_id) - create_story_detail(data) + def call + data = get_story_detail(story_id) + create_story_detail(data) end - private def get_story_detail(story_id) - url = URI.parse("https://hacker-news.firebaseio.com/v0/item/#{story_id}.json?") http = Net::HTTP.new(url.host, url.port) http.use_ssl = (url.scheme == 'https') request = Net::HTTP::Get.new(url) request['Content-Type'] = 'application/json' - - http.request(request).body + http.request(request).body end def create_story_detail(data) - - data = JSON.parse(data) if data.present? - @news_detail = NewsDetail.new(hn_id: data["id"], url: data["url"], - author: data["by"], score: data["score"], title: data["title"], - story_type: data["type"], comment_count: data["descendants"]) + @news_detail = NewsDetail.new(hn_id: data['id'], url: data['url'], + author: data['by'], score: data['score'], title: data['title'], + story_type: data['type'], comment_count: data['descendants']) if @news_detail.save - Result.new(true, nil, "") + Result.new(true, nil, '') else - Result.new(false, data["hn_id"], 'failed saving HN details') + Result.new(false, data['hn_id'], 'failed saving HN details') end else Result.new(false, nil, 'failed saving HN details') end - - - end end -end \ No newline at end of file +end diff --git a/app/services/hacker_news/get_story_ids.rb b/app/services/hacker_news/get_story_ids.rb index 0825d94e..093ab39c 100644 --- a/app/services/hacker_news/get_story_ids.rb +++ b/app/services/hacker_news/get_story_ids.rb @@ -1,18 +1,17 @@ module HackerNews class GetStoryIds < Base - def call response = get_new_stories if response.class.name == 'Net::HTTPOK' ## get news item details. - + story_ids = get_new_stories - story_ids = JSON.parse(response.body) - Result.new(true, story_ids ,'' ) + story_ids = JSON.parse(response.body) + Result.new(true, story_ids, '') else Result.new(false, nil, 'Request to HN failed') end end end -end \ No newline at end of file +end diff --git a/app/sidekiq/poll_hacker_news_job.rb b/app/sidekiq/poll_hacker_news_job.rb index d40edea7..d908fc89 100644 --- a/app/sidekiq/poll_hacker_news_job.rb +++ b/app/sidekiq/poll_hacker_news_job.rb @@ -1,31 +1,28 @@ - class PollHackerNewsJob include Sidekiq::Job - def perform(*args) + def perform(*_args) puts 'polling Hacker News' ## If no news deatilas exist create intial set of them - - if NewsDetail.count == 0 + + if NewsDetail.count == 0 result = HackerNews::GetStoryIds.new.call result.data.each do |story_id| HackerNews::CreateItemDetail.new(story_id).call end end - most_recent_story = NewsDetail.most_recent_story.try(:hn_id) || 0 - if most_recent_story < HackerNews::Base.new.newest_story_id - puts "adding new story" - + most_recent_story = NewsDetail.most_recent_story.try(:hn_id) || 0 + if most_recent_story < HackerNews::Base.new.newest_story_id + puts 'adding new story' + story_id_result = HackerNews::GetStoryIds.new.call - + story_ids = story_id_result.data - result = HackerNews::AddNewStories.new(story_ids).call + result = HackerNews::AddNewStories.new(story_ids).call puts "#{result.success? ? ' New stories added' : result.errors}" else puts 'No new stories' end - end - end diff --git a/app/views/news_details/index.html.erb b/app/views/news_details/index.html.erb index 82c939a3..edf8b0d0 100644 --- a/app/views/news_details/index.html.erb +++ b/app/views/news_details/index.html.erb @@ -1,4 +1,4 @@ -

    Recent Top Stories

    +

    Recent Stories

    <%= paginate @news_details %> diff --git a/app/views/news_details/liked_index.html.erb b/app/views/news_details/liked_index.html.erb index 66527728..35a717ef 100644 --- a/app/views/news_details/liked_index.html.erb +++ b/app/views/news_details/liked_index.html.erb @@ -1,4 +1,4 @@ -

    Liked Top Stories

    +

    Liked Stories

    <%= link_to "Log out", destroy_user_session_path, method: :delete, class: "btn btn-danger" %> <%= link_to "Recent Top Stories", news_details_path %> diff --git a/db/migrate/20180228212101_devise_create_users.rb b/db/migrate/20180228212101_devise_create_users.rb index c6808c47..6e7fe031 100644 --- a/db/migrate/20180228212101_devise_create_users.rb +++ b/db/migrate/20180228212101_devise_create_users.rb @@ -7,8 +7,8 @@ def change t.string :last_name ## Database authenticatable - t.string :email, null: false, default: "" - t.string :encrypted_password, null: false, default: "" + t.string :email, null: false, default: '' + t.string :encrypted_password, null: false, default: '' ## Recoverable t.string :reset_password_token @@ -35,7 +35,6 @@ def change # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at - t.timestamps null: false end diff --git a/db/migrate/20240812194904_create_news_details.rb b/db/migrate/20240812194904_create_news_details.rb index cfdf4407..f313cecb 100644 --- a/db/migrate/20240812194904_create_news_details.rb +++ b/db/migrate/20240812194904_create_news_details.rb @@ -2,12 +2,12 @@ class CreateNewsDetails < ActiveRecord::Migration[7.0] def change create_table :news_details do |t| t.string :author # By in HN - t.integer :comment_count # Decendents in HN - t.integer :hn_id # HN id - t.string :url #HN url - t.integer :score #HN score - t.string :title #HN story title - t.string :story_type #HN story type + t.integer :comment_count # Decendents in HN + t.integer :hn_id # HN id + t.string :url # HN url + t.integer :score # HN score + t.string :title # HN story title + t.string :story_type # HN story type t.timestamps end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index b51dc1c3..fed44d41 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,16 +1,16 @@ require 'rails_helper' describe User do - context "creating a new user" do + context 'creating a new user' do let(:attrs) do { first_name: :foo, last_name: :bar, email: 'f@b.c', password: 'foobar123' } end - it "should have first, last, email" do - expect { User.create(attrs) }.to change{ User.count }.by(1) + it 'should have first, last, email' do + expect { User.create(attrs) }.to change { User.count }.by(1) end - it "should require a password" do + it 'should require a password' do expect(User.new(attrs.except(:password))).to be_invalid end end diff --git a/spec/services/hacker_news/add_new_stories_spec.rb b/spec/services/hacker_news/add_new_stories_spec.rb index 6771b7dd..95df3ca4 100644 --- a/spec/services/hacker_news/add_new_stories_spec.rb +++ b/spec/services/hacker_news/add_new_stories_spec.rb @@ -1,33 +1,30 @@ require 'rails_helper' - RSpec.describe HackerNews::AddNewStories do - subject(:service) { described_class} - + subject(:service) { described_class } + describe '#call' do context 'when service is called' do it 'adds new stories' do - result = service.new([41234588]).call - expect(result.success?).to be true + result = service.new([41_234_588]).call + expect(result.success?).to be true end it 'fails to add' do - result = service.new([99999999111]).call - expect(result.success?).to be false + result = service.new([99_999_999_111]).call + expect(result.success?).to be false end end context 'does not add if story is already save in NewsDetail' do it 'does not save' do - service.new([41229573, 41229555, 41235733, 41235723, 41235721]).call - - service.new([41229600, 41229597, 41229595, 41229589, 41229582, - 41229573, 41229555, 41235733, 41235723, 41235721]).call + service.new([41_229_573, 41_229_555, 41_235_733, 41_235_723, 41_235_721]).call + + service.new([41_229_600, 41_229_597, 41_229_595, 41_229_589, 41_229_582, + 41_229_573, 41_229_555, 41_235_733, 41_235_723, 41_235_721]).call - - expect(NewsDetail.count).to eq(10) - + expect(NewsDetail.count).to eq(10) end end end -end \ No newline at end of file +end diff --git a/spec/services/hacker_news/create_item_details_spec.rb b/spec/services/hacker_news/create_item_details_spec.rb index ce65714e..cf9ca8cb 100644 --- a/spec/services/hacker_news/create_item_details_spec.rb +++ b/spec/services/hacker_news/create_item_details_spec.rb @@ -1,29 +1,26 @@ require 'rails_helper' RSpec.describe HackerNews::CreateItemDetail do - subject(:service) {described_class} - + subject(:service) { described_class } describe '#call' do context 'creates new NewsDetail from HN story ID' do - it 'saves new news detail' do - result = service.new(41234585).call + result = service.new(41_234_585).call expect(result.success?).to be true end it 'does not save duplicates' do - service.new(41234585).call - result = service.new(41234585).call + service.new(41_234_585).call + result = service.new(41_234_585).call expect(result.success?).to be false end it 'does not save invalid data' do - result = service.new(4123458599999).call + result = service.new(4_123_458_599_999).call expect(result.success?).to be false end end - end -end \ No newline at end of file +end diff --git a/spec/services/hacker_news/get_story_ids_spec.rb b/spec/services/hacker_news/get_story_ids_spec.rb index 9337e0db..0864109e 100644 --- a/spec/services/hacker_news/get_story_ids_spec.rb +++ b/spec/services/hacker_news/get_story_ids_spec.rb @@ -1,23 +1,15 @@ require 'rails_helper' - RSpec.describe HackerNews::GetStoryIds do subject(:service) { described_class.new } - + describe '#call' do context 'when service is called' do it 'gets storu ids' do result = service.call - + expect(result.success?).to be true - end end - - end - - - - -end \ No newline at end of file +end diff --git a/spec/sidekiq/poll_hacker_news_job_spec.rb b/spec/sidekiq/poll_hacker_news_job_spec.rb index 0675ece1..49a4e8e0 100644 --- a/spec/sidekiq/poll_hacker_news_job_spec.rb +++ b/spec/sidekiq/poll_hacker_news_job_spec.rb @@ -1,20 +1,18 @@ require 'rails_helper' -RSpec.describe PollHackerNewsJob do - subject(:service) { described_class} +RSpec.describe PollHackerNewsJob do + subject(:service) { described_class } - - let(:news_detail) { NewsDetail.create(hn_id: 1)} + let(:news_detail) { NewsDetail.create(hn_id: 1) } describe '#perform' do it 'intial perfrom populates db' do - - service.new.perform - expect(NewsDetail.count).to eq(500) + service.new.perform + expect(NewsDetail.count > 0).to be true end it 'addtional performs will add to db' do news_detail service.new.perform - expect(NewsDetail.count).to eq(501) + expect(NewsDetail.count > 1).to be true end end end diff --git a/test/application_system_test_case.rb b/test/application_system_test_case.rb index d19212ab..23701b43 100644 --- a/test/application_system_test_case.rb +++ b/test/application_system_test_case.rb @@ -1,4 +1,4 @@ -require "test_helper" +require 'test_helper' class ApplicationSystemTestCase < ActionDispatch::SystemTestCase driven_by :selenium, using: :chrome, screen_size: [1400, 1400] From 1b2e9c7cee9b944e8bd241fdc1bde31a0f3c6589 Mon Sep 17 00:00:00 2001 From: John Verdone Date: Tue, 13 Aug 2024 11:04:37 -0400 Subject: [PATCH 14/16] rubocop --- Gemfile | 2 ++ Gemfile.lock | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/Gemfile b/Gemfile index 897c9314..0a51473a 100644 --- a/Gemfile +++ b/Gemfile @@ -27,6 +27,8 @@ group :development do gem 'spring' gem 'web-console' gem 'listen' + gem 'rubocop', require: false + end group :development, :test do diff --git a/Gemfile.lock b/Gemfile.lock index 5a36ee4c..90270b0f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -68,6 +68,7 @@ GEM tzinfo (~> 2.0) addressable (2.8.7) public_suffix (>= 2.0.2, < 7.0) + ast (2.4.2) base64 (0.2.0) bcrypt (3.1.20) bindex (0.8.1) @@ -117,6 +118,7 @@ GEM jbuilder (2.12.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) + json (2.7.2) kaminari (1.2.2) activesupport (>= 4.1.0) kaminari-actionview (= 1.2.2) @@ -129,6 +131,7 @@ GEM activerecord kaminari-core (= 1.2.2) kaminari-core (1.2.2) + language_server-protocol (3.17.0.3) listen (3.9.0) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -159,6 +162,10 @@ GEM nokogiri (1.16.7-x86_64-darwin) racc (~> 1.4) orm_adapter (0.5.0) + parallel (1.26.2) + parser (3.3.4.2) + ast (~> 2.4.1) + racc pg (1.5.7) pry (0.14.2) coderay (~> 1.1) @@ -201,6 +208,7 @@ GEM rake (>= 12.2) thor (~> 1.0) zeitwerk (~> 2.5) + rainbow (3.1.1) rake (13.2.1) rb-fsevent (0.11.2) rb-inotify (0.11.1) @@ -229,6 +237,20 @@ GEM rspec-mocks (~> 3.13) rspec-support (~> 3.13) rspec-support (3.13.1) + rubocop (1.65.1) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.4, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.31.1, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.32.0) + parser (>= 3.3.1.0) + ruby-progressbar (1.13.0) rubyzip (2.3.2) rufus-scheduler (3.9.1) fugit (~> 1.1, >= 1.1.6) @@ -276,6 +298,7 @@ GEM concurrent-ruby (~> 1.0) uglifier (4.2.0) execjs (>= 0.3.0, < 3) + unicode-display_width (2.5.0) warden (1.2.9) rack (>= 2.0.9) web-console (4.2.1) @@ -310,6 +333,7 @@ DEPENDENCIES rails (~> 7.0.3) redis rspec-rails + rubocop sass-rails selenium-webdriver sidekiq From ce8c8d56b44c3213c7443beecf6f84b38125d4c0 Mon Sep 17 00:00:00 2001 From: John Verdone Date: Tue, 13 Aug 2024 11:04:47 -0400 Subject: [PATCH 15/16] linting --- config/routes.rb | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index 3262718a..48cccb16 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -3,15 +3,12 @@ root to: 'news_details#index' resources :news_details, only: [:index] do - collection do - get :liked_index - end + collection do + get :liked_index + end member do patch :upvote patch :downvote - end end - - end From 1cf905d89a5e66393f5c7df45672af1a49d7ff5b Mon Sep 17 00:00:00 2001 From: John Verdone Date: Tue, 13 Aug 2024 11:05:36 -0400 Subject: [PATCH 16/16] linting of boiler plate files --- bin/rake | 2 +- bin/setup | 3 +- bin/spring | 2 +- bin/update | 2 +- bin/yarn | 12 ++-- config/application.rb | 1 - config/environments/development.rb | 2 - config/environments/production.rb | 4 +- config/initializers/sidekiq.rb | 5 +- config/puma.rb | 6 +- config/spring.rb | 4 +- db/schema.rb | 73 +++++++++++------------ db/seeds.rb | 24 ++++---- spec/rails_helper.rb | 8 +-- spec/spec_helper.rb | 96 +++++++++++++++--------------- test/test_helper.rb | 2 +- 16 files changed, 116 insertions(+), 130 deletions(-) diff --git a/bin/rake b/bin/rake index d87d5f57..0ba8c48c 100755 --- a/bin/rake +++ b/bin/rake @@ -1,6 +1,6 @@ #!/usr/bin/env ruby begin - load File.expand_path('../spring', __FILE__) + load File.expand_path('spring', __dir__) rescue LoadError => e raise unless e.message.include?('spring') end diff --git a/bin/setup b/bin/setup index 78c4e861..b2293a35 100755 --- a/bin/setup +++ b/bin/setup @@ -4,7 +4,7 @@ require 'fileutils' include FileUtils # path to your application root. -APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) +APP_ROOT = Pathname.new File.expand_path('..', __dir__) def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") @@ -21,7 +21,6 @@ chdir APP_ROOT do # Install JavaScript dependencies if using Yarn # system('bin/yarn') - # puts "\n== Copying sample files ==" # unless File.exist?('config/database.yml') # cp 'config/database.yml.sample', 'config/database.yml' diff --git a/bin/spring b/bin/spring index fb2ec2eb..991bd4ef 100755 --- a/bin/spring +++ b/bin/spring @@ -8,7 +8,7 @@ unless defined?(Spring) require 'bundler' lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read) - spring = lockfile.specs.detect { |spec| spec.name == "spring" } + spring = lockfile.specs.detect { |spec| spec.name == 'spring' } if spring Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path gem 'spring', spring.version diff --git a/bin/update b/bin/update index a8e4462f..32326c74 100755 --- a/bin/update +++ b/bin/update @@ -4,7 +4,7 @@ require 'fileutils' include FileUtils # path to your application root. -APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) +APP_ROOT = Pathname.new File.expand_path('..', __dir__) def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") diff --git a/bin/yarn b/bin/yarn index c2bacef8..fc0bd659 100755 --- a/bin/yarn +++ b/bin/yarn @@ -1,11 +1,9 @@ #!/usr/bin/env ruby VENDOR_PATH = File.expand_path('..', __dir__) Dir.chdir(VENDOR_PATH) do - begin - exec "yarnpkg #{ARGV.join(" ")}" - rescue Errno::ENOENT - $stderr.puts "Yarn executable was not detected in the system." - $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" - exit 1 - end + exec "yarnpkg #{ARGV.join(' ')}" +rescue Errno::ENOENT + warn 'Yarn executable was not detected in the system.' + warn 'Download Yarn at https://yarnpkg.com/en/docs/install' + exit 1 end diff --git a/config/application.rb b/config/application.rb index 5763fbad..9c44baff 100644 --- a/config/application.rb +++ b/config/application.rb @@ -15,6 +15,5 @@ class Application < Rails::Application # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. config.active_record.legacy_connection_handling = false - end end diff --git a/config/environments/development.rb b/config/environments/development.rb index e43a9f50..5187e221 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -51,6 +51,4 @@ # Use an evented file watcher to asynchronously detect changes in source code, # routes, locales, etc. This feature depends on the listen gem. config.file_watcher = ActiveSupport::EventedFileUpdateChecker - - end diff --git a/config/environments/production.rb b/config/environments/production.rb index 73aa41e6..97009666 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -52,7 +52,7 @@ config.log_level = :debug # Prepend all log lines with the following tags. - config.log_tags = [ :request_id ] + config.log_tags = [:request_id] # Use a different cache store in production. # config.cache_store = :mem_cache_store @@ -80,7 +80,7 @@ # require 'syslog/logger' # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') - if ENV["RAILS_LOG_TO_STDOUT"].present? + if ENV['RAILS_LOG_TO_STDOUT'].present? logger = ActiveSupport::Logger.new(STDOUT) logger.formatter = config.log_formatter config.logger = ActiveSupport::TaggedLogging.new(logger) diff --git a/config/initializers/sidekiq.rb b/config/initializers/sidekiq.rb index 8f3de0b4..7d0429e6 100644 --- a/config/initializers/sidekiq.rb +++ b/config/initializers/sidekiq.rb @@ -1,10 +1,9 @@ require 'sidekiq' require 'sidekiq-scheduler' - Sidekiq.configure_server do |config| config.on(:startup) do - Sidekiq.schedule = YAML.load_file(File.expand_path('../../sidekiq_scheduler.yml', __FILE__)) + Sidekiq.schedule = YAML.load_file(File.expand_path('../sidekiq_scheduler.yml', __dir__)) SidekiqScheduler::Scheduler.instance.reload_schedule! end -end \ No newline at end of file +end diff --git a/config/puma.rb b/config/puma.rb index 1e19380d..ccda173c 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -4,16 +4,16 @@ # the maximum value specified for Puma. Default is set to 5 threads for minimum # and maximum; this matches the default thread size of Active Record. # -threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +threads_count = ENV.fetch('RAILS_MAX_THREADS') { 5 } threads threads_count, threads_count # Specifies the `port` that Puma will listen on to receive requests; default is 3000. # -port ENV.fetch("PORT") { 3000 } +port ENV.fetch('PORT') { 3000 } # Specifies the `environment` that Puma will run in. # -environment ENV.fetch("RAILS_ENV") { "development" } +environment ENV.fetch('RAILS_ENV') { 'development' } # Specifies the number of `workers` to boot in clustered mode. # Workers are forked webserver processes. If using threads and workers together diff --git a/config/spring.rb b/config/spring.rb index c9119b40..9fa7863f 100644 --- a/config/spring.rb +++ b/config/spring.rb @@ -1,6 +1,6 @@ -%w( +%w[ .ruby-version .rbenv-vars tmp/restart.txt tmp/caching-dev.txt -).each { |path| Spring.watch(path) } +].each { |path| Spring.watch(path) } diff --git a/db/schema.rb b/db/schema.rb index 4e9d6e2e..89b70f94 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,48 +10,47 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2024_08_13_041304) do +ActiveRecord::Schema[7.0].define(version: 20_240_813_041_304) do # These are extensions that must be enabled in order to support this database - enable_extension "plpgsql" + enable_extension 'plpgsql' - create_table "news_details", force: :cascade do |t| - t.string "author" - t.integer "comment_count" - t.integer "hn_id" - t.string "url" - t.integer "score" - t.string "title" - t.string "story_type" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + create_table 'news_details', force: :cascade do |t| + t.string 'author' + t.integer 'comment_count' + t.integer 'hn_id' + t.string 'url' + t.integer 'score' + t.string 'title' + t.string 'story_type' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false end - create_table "news_details_users", id: false, force: :cascade do |t| - t.bigint "user_id", null: false - t.bigint "news_detail_id", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["news_detail_id"], name: "index_news_details_users_on_news_detail_id" - t.index ["user_id"], name: "index_news_details_users_on_user_id" + create_table 'news_details_users', id: false, force: :cascade do |t| + t.bigint 'user_id', null: false + t.bigint 'news_detail_id', null: false + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + t.index ['news_detail_id'], name: 'index_news_details_users_on_news_detail_id' + t.index ['user_id'], name: 'index_news_details_users_on_user_id' end - create_table "users", force: :cascade do |t| - t.string "first_name" - t.string "last_name" - t.string "email", default: "", null: false - t.string "encrypted_password", default: "", null: false - t.string "reset_password_token" - t.datetime "reset_password_sent_at", precision: nil - t.datetime "remember_created_at", precision: nil - t.integer "sign_in_count", default: 0, null: false - t.datetime "current_sign_in_at", precision: nil - t.datetime "last_sign_in_at", precision: nil - t.inet "current_sign_in_ip" - t.inet "last_sign_in_ip" - t.datetime "created_at", precision: nil, null: false - t.datetime "updated_at", precision: nil, null: false - t.index ["email"], name: "index_users_on_email", unique: true - t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true + create_table 'users', force: :cascade do |t| + t.string 'first_name' + t.string 'last_name' + t.string 'email', default: '', null: false + t.string 'encrypted_password', default: '', null: false + t.string 'reset_password_token' + t.datetime 'reset_password_sent_at', precision: nil + t.datetime 'remember_created_at', precision: nil + t.integer 'sign_in_count', default: 0, null: false + t.datetime 'current_sign_in_at', precision: nil + t.datetime 'last_sign_in_at', precision: nil + t.inet 'current_sign_in_ip' + t.inet 'last_sign_in_ip' + t.datetime 'created_at', precision: nil, null: false + t.datetime 'updated_at', precision: nil, null: false + t.index ['email'], name: 'index_users_on_email', unique: true + t.index ['reset_password_token'], name: 'index_users_on_reset_password_token', unique: true end - end diff --git a/db/seeds.rb b/db/seeds.rb index 231b90ad..b0afe6c3 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,17 +1,17 @@ User.find_or_initialize_by(email: 'DonaldGMiller@example.com').update({ - first_name: 'Donald', - last_name: 'Miller', - password: 'eeMaev2shai' -}) + first_name: 'Donald', + last_name: 'Miller', + password: 'eeMaev2shai' + }) User.find_or_initialize_by(email: 'LawrenceWGrant@example.com').update({ - first_name: 'Lawrence', - last_name: 'Grant', - password: 'ahR7iecai' -}) + first_name: 'Lawrence', + last_name: 'Grant', + password: 'ahR7iecai' + }) User.find_or_initialize_by(email: 'MargeRWilliams@example.com').update({ - first_name: 'Marge', - last_name: 'Williams', - password: 'Aechugh1ie' -}) + first_name: 'Marge', + last_name: 'Williams', + password: 'Aechugh1ie' + }) diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index b1131ddd..2cedbfff 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -1,9 +1,9 @@ # This file is copied to spec/ when you run 'rails generate rspec:install' require 'spec_helper' ENV['RAILS_ENV'] ||= 'test' -require File.expand_path('../../config/environment', __FILE__) +require File.expand_path('../config/environment', __dir__) # Prevent database truncation if the environment is production -abort("The Rails environment is running in production mode!") if Rails.env.production? +abort('The Rails environment is running in production mode!') if Rails.env.production? require 'rspec/rails' # Add additional requires below this line. Rails is not loaded until this point! @@ -26,8 +26,6 @@ # If you are not using ActiveRecord, you can remove this line. ActiveRecord::Migration.maintain_test_schema! - - RSpec.configure do |config| # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" @@ -37,8 +35,6 @@ # instead of true. config.use_transactional_fixtures = true - - # RSpec Rails can automatically mix in different behaviours to your tests # based on their file location, for example enabling you to call `get` and # `post` in specs under `spec/controllers`. diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index ce33d66d..15a38725 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -44,53 +44,51 @@ # triggering implicit auto-inclusion in groups with matching metadata. config.shared_context_metadata_behavior = :apply_to_host_groups -# The settings below are suggested to provide a good initial experience -# with RSpec, but feel free to customize to your heart's content. -=begin - # This allows you to limit a spec run to individual examples or groups - # you care about by tagging them with `:focus` metadata. When nothing - # is tagged with `:focus`, all examples get run. RSpec also provides - # aliases for `it`, `describe`, and `context` that include `:focus` - # metadata: `fit`, `fdescribe` and `fcontext`, respectively. - config.filter_run_when_matching :focus - - # Allows RSpec to persist some state between runs in order to support - # the `--only-failures` and `--next-failure` CLI options. We recommend - # you configure your source control system to ignore this file. - config.example_status_persistence_file_path = "spec/examples.txt" - - # Limits the available syntax to the non-monkey patched syntax that is - # recommended. For more details, see: - # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ - # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ - # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode - config.disable_monkey_patching! - - # Many RSpec users commonly either run the entire suite or an individual - # file, and it's useful to allow more verbose output when running an - # individual spec file. - if config.files_to_run.one? - # Use the documentation formatter for detailed output, - # unless a formatter has already been configured - # (e.g. via a command-line flag). - config.default_formatter = "doc" - end - - # Print the 10 slowest examples and example groups at the - # end of the spec run, to help surface which specs are running - # particularly slow. - config.profile_examples = 10 - - # Run specs in random order to surface order dependencies. If you find an - # order dependency and want to debug it, you can fix the order by providing - # the seed, which is printed after each run. - # --seed 1234 - config.order = :random - - # Seed global randomization in this process using the `--seed` CLI option. - # Setting this allows you to use `--seed` to deterministically reproduce - # test failures related to randomization by passing the same `--seed` value - # as the one that triggered the failure. - Kernel.srand config.seed -=end + # The settings below are suggested to provide a good initial experience + # with RSpec, but feel free to customize to your heart's content. + # # This allows you to limit a spec run to individual examples or groups + # # you care about by tagging them with `:focus` metadata. When nothing + # # is tagged with `:focus`, all examples get run. RSpec also provides + # # aliases for `it`, `describe`, and `context` that include `:focus` + # # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + # config.filter_run_when_matching :focus + # + # # Allows RSpec to persist some state between runs in order to support + # # the `--only-failures` and `--next-failure` CLI options. We recommend + # # you configure your source control system to ignore this file. + # config.example_status_persistence_file_path = "spec/examples.txt" + # + # # Limits the available syntax to the non-monkey patched syntax that is + # # recommended. For more details, see: + # # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/ + # # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ + # # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode + # config.disable_monkey_patching! + # + # # Many RSpec users commonly either run the entire suite or an individual + # # file, and it's useful to allow more verbose output when running an + # # individual spec file. + # if config.files_to_run.one? + # # Use the documentation formatter for detailed output, + # # unless a formatter has already been configured + # # (e.g. via a command-line flag). + # config.default_formatter = "doc" + # end + # + # # Print the 10 slowest examples and example groups at the + # # end of the spec run, to help surface which specs are running + # # particularly slow. + # config.profile_examples = 10 + # + # # Run specs in random order to surface order dependencies. If you find an + # # order dependency and want to debug it, you can fix the order by providing + # # the seed, which is printed after each run. + # # --seed 1234 + # config.order = :random + # + # # Seed global randomization in this process using the `--seed` CLI option. + # # Setting this allows you to use `--seed` to deterministically reproduce + # # test failures related to randomization by passing the same `--seed` value + # # as the one that triggered the failure. + # Kernel.srand config.seed end diff --git a/test/test_helper.rb b/test/test_helper.rb index 92e39b2d..88d8f433 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,5 +1,5 @@ ENV['RAILS_ENV'] ||= 'test' -require File.expand_path('../../config/environment', __FILE__) +require File.expand_path('../config/environment', __dir__) require 'rails/test_help' class ActiveSupport::TestCase