From 747b61a1fe81bbdc55a26e1be61c94ccaa4f1105 Mon Sep 17 00:00:00 2001 From: Justin Ko <14007+justinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 13:22:06 -0700 Subject: [PATCH 1/4] Done --- Gemfile | 2 ++ Gemfile.lock | 4 +++ app/controllers/quotes_controller.rb | 6 ++++ app/controllers/ratings_controller.rb | 19 +++++++++++ app/lib/ron_swanson_quotes.rb | 5 +++ app/models/quote.rb | 9 +++++ app/models/rating.rb | 8 +++++ app/views/quotes/show.html.erb | 9 +++++ config/routes.rb | 6 ++-- .../20231109024110_initial_migration.rb | 15 ++++++++ db/schema.rb | 34 +++++++++++++++++++ 11 files changed, 115 insertions(+), 2 deletions(-) create mode 100644 app/controllers/quotes_controller.rb create mode 100644 app/controllers/ratings_controller.rb create mode 100644 app/lib/ron_swanson_quotes.rb create mode 100644 app/models/quote.rb create mode 100644 app/models/rating.rb create mode 100644 app/views/quotes/show.html.erb create mode 100644 db/migrate/20231109024110_initial_migration.rb create mode 100644 db/schema.rb diff --git a/Gemfile b/Gemfile index cfaa680..2e9b44f 100644 --- a/Gemfile +++ b/Gemfile @@ -47,6 +47,8 @@ gem "bootsnap", require: false # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] # gem "image_processing", "~> 1.2" +gem "httpx" + group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem gem "debug", platforms: %i[ mri windows ] diff --git a/Gemfile.lock b/Gemfile.lock index 0a77b24..974a1d8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -103,6 +103,9 @@ GEM erubi (1.12.0) globalid (1.2.1) activesupport (>= 6.1) + http-2-next (1.0.1) + httpx (1.1.1) + http-2-next (>= 1.0.1) i18n (1.14.1) concurrent-ruby (~> 1.0) importmap-rails (1.2.3) @@ -254,6 +257,7 @@ DEPENDENCIES bootsnap capybara debug + httpx importmap-rails jbuilder pg (~> 1.1) diff --git a/app/controllers/quotes_controller.rb b/app/controllers/quotes_controller.rb new file mode 100644 index 0000000..beb60a8 --- /dev/null +++ b/app/controllers/quotes_controller.rb @@ -0,0 +1,6 @@ +class QuotesController < ApplicationController + def show + @quote = Quote.sample + @rating = @quote.ratings.new + end +end diff --git a/app/controllers/ratings_controller.rb b/app/controllers/ratings_controller.rb new file mode 100644 index 0000000..6cff8dd --- /dev/null +++ b/app/controllers/ratings_controller.rb @@ -0,0 +1,19 @@ +class RatingsController < ApplicationController + def create + @quote = Quote.find(params[:quote_id]) + @rating = @quote.ratings.new(rating_params) + @rating.ip = request.remote_ip + + if @rating.save + redirect_to root_url + else + render "quotes/show" + end + end + + private + + def rating_params + params.require(:rating).permit(:number) + end +end diff --git a/app/lib/ron_swanson_quotes.rb b/app/lib/ron_swanson_quotes.rb new file mode 100644 index 0000000..78674a1 --- /dev/null +++ b/app/lib/ron_swanson_quotes.rb @@ -0,0 +1,5 @@ +module RonSwansonQuotes + def self.get + HTTPX.get("https://ron-swanson-quotes.herokuapp.com/v2/quotes").json.first + end +end diff --git a/app/models/quote.rb b/app/models/quote.rb new file mode 100644 index 0000000..7cf294d --- /dev/null +++ b/app/models/quote.rb @@ -0,0 +1,9 @@ +class Quote < ApplicationRecord + has_many :ratings, dependent: :destroy + + validates :text, presence: true, uniqueness: true + + def self.sample + find_or_create_by!(text: RonSwansonQuotes.get) + end +end diff --git a/app/models/rating.rb b/app/models/rating.rb new file mode 100644 index 0000000..5a279a9 --- /dev/null +++ b/app/models/rating.rb @@ -0,0 +1,8 @@ +class Rating < ApplicationRecord + NUMBER_RANGE = 1..5 + + belongs_to :quote + + validates :number, presence: true, numericality: {in: NUMBER_RANGE} + validates :ip, presence: true, uniqueness: true +end diff --git a/app/views/quotes/show.html.erb b/app/views/quotes/show.html.erb new file mode 100644 index 0000000..9ea47ff --- /dev/null +++ b/app/views/quotes/show.html.erb @@ -0,0 +1,9 @@ +

+ <%= @quote.text %> +

+ +<%= form_with model: [@quote, @rating], data: {turbo: false} do |f| %> + <%= f.object.errors.full_messages.to_sentence %> + <%= f.number_field :number, in: Rating::NUMBER_RANGE %> + <%= f.submit %> +<% end %> diff --git a/config/routes.rb b/config/routes.rb index a125ef0..3e1ba46 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -5,6 +5,8 @@ # Can be used by load balancers and uptime monitors to verify that the app is live. get "up" => "rails/health#show", as: :rails_health_check - # Defines the root path route ("/") - # root "posts#index" + resources :quotes, only: :show do + resources :ratings, only: :create + end + root "quotes#show" end diff --git a/db/migrate/20231109024110_initial_migration.rb b/db/migrate/20231109024110_initial_migration.rb new file mode 100644 index 0000000..4a43a03 --- /dev/null +++ b/db/migrate/20231109024110_initial_migration.rb @@ -0,0 +1,15 @@ +class InitialMigration < ActiveRecord::Migration[7.1] + def change + create_table :quotes do |t| + t.text :text, null: false + t.timestamps + end + + create_table :ratings do |t| + t.belongs_to :quote, foreign_key: true + t.integer :number, null: false + t.string :ip, null: false, index: { unique: true } + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..90b26b7 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,34 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. +# +# It's strongly recommended that you check this file into your version control system. + +ActiveRecord::Schema[7.1].define(version: 2023_11_09_024110) do + # These are extensions that must be enabled in order to support this database + enable_extension "plpgsql" + + create_table "quotes", force: :cascade do |t| + t.text "text", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "ratings", force: :cascade do |t| + t.bigint "quote_id" + t.integer "number", null: false + t.string "ip", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["ip"], name: "index_ratings_on_ip", unique: true + t.index ["quote_id"], name: "index_ratings_on_quote_id" + end + + add_foreign_key "ratings", "quotes" +end From fd72ed60b373906bf093472c7760f665d2484601 Mon Sep 17 00:00:00 2001 From: Justin Ko <14007+justinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 13:29:53 -0700 Subject: [PATCH 2/4] add average rating --- app/views/quotes/show.html.erb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/views/quotes/show.html.erb b/app/views/quotes/show.html.erb index 9ea47ff..210997d 100644 --- a/app/views/quotes/show.html.erb +++ b/app/views/quotes/show.html.erb @@ -2,6 +2,11 @@ <%= @quote.text %> +

+ Average rating: + <%= @quote.ratings.average(:number) %> +

+ <%= form_with model: [@quote, @rating], data: {turbo: false} do |f| %> <%= f.object.errors.full_messages.to_sentence %> <%= f.number_field :number, in: Rating::NUMBER_RANGE %> From 17fa6684cdb99333fe29f031adf66b59d92b5d67 Mon Sep 17 00:00:00 2001 From: Justin Ko <14007+justinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 13:37:15 -0700 Subject: [PATCH 3/4] don't disable turbo --- app/controllers/ratings_controller.rb | 2 +- app/views/quotes/show.html.erb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/ratings_controller.rb b/app/controllers/ratings_controller.rb index 6cff8dd..b569f24 100644 --- a/app/controllers/ratings_controller.rb +++ b/app/controllers/ratings_controller.rb @@ -7,7 +7,7 @@ def create if @rating.save redirect_to root_url else - render "quotes/show" + render "quotes/show", status: :unprocessable_entity end end diff --git a/app/views/quotes/show.html.erb b/app/views/quotes/show.html.erb index 210997d..e43ff1c 100644 --- a/app/views/quotes/show.html.erb +++ b/app/views/quotes/show.html.erb @@ -7,7 +7,7 @@ <%= @quote.ratings.average(:number) %>

-<%= form_with model: [@quote, @rating], data: {turbo: false} do |f| %> +<%= form_with model: [@quote, @rating] do |f| %> <%= f.object.errors.full_messages.to_sentence %> <%= f.number_field :number, in: Rating::NUMBER_RANGE %> <%= f.submit %> From 491a5bdfee18b2510b63938837585289dfb4cded Mon Sep 17 00:00:00 2001 From: Justin Ko <14007+justinko@users.noreply.github.com> Date: Thu, 9 Nov 2023 13:45:26 -0700 Subject: [PATCH 4/4] add unique index to quote text --- db/migrate/20231109024110_initial_migration.rb | 2 +- db/schema.rb | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/db/migrate/20231109024110_initial_migration.rb b/db/migrate/20231109024110_initial_migration.rb index 4a43a03..acc7abd 100644 --- a/db/migrate/20231109024110_initial_migration.rb +++ b/db/migrate/20231109024110_initial_migration.rb @@ -1,7 +1,7 @@ class InitialMigration < ActiveRecord::Migration[7.1] def change create_table :quotes do |t| - t.text :text, null: false + t.text :text, null: false, index: { unique: true } t.timestamps end diff --git a/db/schema.rb b/db/schema.rb index 90b26b7..ce2860b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -18,6 +18,7 @@ t.text "text", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["text"], name: "index_quotes_on_text", unique: true end create_table "ratings", force: :cascade do |t|