From f51fac37a058758558c2b230e31c8dd6aba8387c Mon Sep 17 00:00:00 2001 From: Tristan Date: Tue, 21 Oct 2025 22:30:12 -0400 Subject: [PATCH 1/4] final touches --- app/controllers/application_controller.rb | 2 +- app/controllers/dashboard_controller.rb | 11 +++ app/controllers/home_controller.rb | 4 ++ app/controllers/samples_controller.rb | 24 +++++++ app/controllers/sessions_controller.rb | 4 +- app/controllers/tracks_controller.rb | 14 ++-- app/controllers/users_controller.rb | 22 ++++++ app/helpers/home_helper.rb | 2 + app/helpers/users_helper.rb | 2 + app/models/artist.rb | 4 +- app/models/sample.rb | 27 +++++++- app/models/track.rb | 19 +++++- app/models/user.rb | 10 ++- app/views/dashboard/index.html.erb | 20 ++++-- app/views/home/index.html.erb | 16 +++++ app/views/layouts/application.html.erb | 40 ++++++----- app/views/samples/new.html.erb | 27 ++++++++ app/views/sessions/new.html.erb | 33 +++++---- app/views/tracks/show.html.erb | 67 +++++++++++++------ app/views/users/create.html.erb | 2 + app/views/users/new.html.erb | 38 +++++++++++ config/routes.rb | 11 ++- ..._add_null_constraint_to_password_digest.rb | 5 ++ ...021407_add_unique_index_to_artists_name.rb | 6 ++ db/schema.rb | 6 +- spec/helpers/home_helper_spec.rb | 15 +++++ spec/helpers/users_helper_spec.rb | 15 +++++ spec/models/sample_spec.rb | 30 +++++++++ spec/requests/dashboard_spec.rb | 9 +++ spec/requests/home_spec.rb | 11 +++ spec/requests/users_spec.rb | 18 +++++ spec/views/home/index.html.erb_spec.rb | 5 ++ spec/views/users/create.html.erb_spec.rb | 5 ++ spec/views/users/new.html.erb_spec.rb | 5 ++ 34 files changed, 455 insertions(+), 74 deletions(-) create mode 100644 app/controllers/home_controller.rb create mode 100644 app/controllers/samples_controller.rb create mode 100644 app/controllers/users_controller.rb create mode 100644 app/helpers/home_helper.rb create mode 100644 app/helpers/users_helper.rb create mode 100644 app/views/home/index.html.erb create mode 100644 app/views/samples/new.html.erb create mode 100644 app/views/users/create.html.erb create mode 100644 app/views/users/new.html.erb create mode 100644 db/migrate/20251021021206_add_null_constraint_to_password_digest.rb create mode 100644 db/migrate/20251021021407_add_unique_index_to_artists_name.rb create mode 100644 spec/helpers/home_helper_spec.rb create mode 100644 spec/helpers/users_helper_spec.rb create mode 100644 spec/models/sample_spec.rb create mode 100644 spec/requests/dashboard_spec.rb create mode 100644 spec/requests/home_spec.rb create mode 100644 spec/requests/users_spec.rb create mode 100644 spec/views/home/index.html.erb_spec.rb create mode 100644 spec/views/users/create.html.erb_spec.rb create mode 100644 spec/views/users/new.html.erb_spec.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index a26e8b4..56476a3 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -14,7 +14,7 @@ def logged_in? def require_admin unless current_user&.role == "admin" flash[:alert] = "You do not have permission to do that." - redirect_to root_path + redirect_to dashboard_path end end diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 91905ae..28dc6cf 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -1,6 +1,17 @@ class DashboardController < ApplicationController + before_action :require_login + def index @recent_tracks = Track.order(created_at: :desc).limit(5) @recent_comments = Comment.order(created_at: :desc).limit(5) end + + private + + def require_login + unless logged_in? + flash[:alert] = "Please log in to access the dashboard" + redirect_to login_path + end + end end diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb new file mode 100644 index 0000000..95f2992 --- /dev/null +++ b/app/controllers/home_controller.rb @@ -0,0 +1,4 @@ +class HomeController < ApplicationController + def index + end +end diff --git a/app/controllers/samples_controller.rb b/app/controllers/samples_controller.rb new file mode 100644 index 0000000..6cc3878 --- /dev/null +++ b/app/controllers/samples_controller.rb @@ -0,0 +1,24 @@ +class SamplesController < ApplicationController + before_action :require_admin + + def new + @sample = Sample.new + @tracks = Track.order(:title) + end + + def create + @sample = Sample.new(sample_params) + if @sample.save + redirect_to dashboard_path, notice: "Sample Connection created!" + else + @tracks = Track.order(:title) + render :new, status: :unprocessable_entity + end + end + + private + + def sample_params + params.require(:sample).permit(:derived_track_id, :source_track_id) + end +end \ No newline at end of file diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 095eeb1..7dc2135 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -5,10 +5,12 @@ def new def create user = User.find_by(username: params[:username]) + + if user&.authenticate(params[:password]) session[:user_id] = user.id session[:role] = user.role - redirect_to root_path, notice: "Logged in as #{user.username}" + redirect_to dashboard_path, notice: "Logged in as #{user.username}" else flash.now[:alert] = "Invalid username or password" render :new, status: :unprocessable_entity diff --git a/app/controllers/tracks_controller.rb b/app/controllers/tracks_controller.rb index 8e6eeb7..3b68ac8 100644 --- a/app/controllers/tracks_controller.rb +++ b/app/controllers/tracks_controller.rb @@ -18,24 +18,28 @@ def new def create @track = Track.new(track_params) - @track.user = User.find_by(username: "Twhite") + @track.user = current_user + if @track.save redirect_to @track, notice: "Track Created!" else + @artists = Artist.alphabetical render :new, status: :unprocessable_entity end end - def edit - @track = Track.find(params[:id]) - end +def edit + @track = Track.find(params[:id]) + @artists = Artist.alphabetical +end def update @track = Track.find(params[:id]) - @track.user = User.find_by(username: "Twhite") + @track.user = current_user if @track.update(track_params) redirect_to @track, notice: "Track Updated" else + @artists = Artist.alphabetical render :edit, status: :unprocessable_entity end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000..0d68b77 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,22 @@ +class UsersController < ApplicationController + def new + @user = User.new + end + + def create + @user = User.new(user_params) + if @user.save + session[:user_id] = @user.id + redirect_to dashboard_path, notice: "Welcome, #{@user.username}!" + else + flash.now[:alert] = @user.errors.full_messages.to_sentence + render :new, status: :unprocessable_entity + end + end + + private + + def user_params + params.require(:user).permit(:username, :email, :password, :password_confirmation) + end +end \ No newline at end of file diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb new file mode 100644 index 0000000..23de56a --- /dev/null +++ b/app/helpers/home_helper.rb @@ -0,0 +1,2 @@ +module HomeHelper +end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb new file mode 100644 index 0000000..2310a24 --- /dev/null +++ b/app/helpers/users_helper.rb @@ -0,0 +1,2 @@ +module UsersHelper +end diff --git a/app/models/artist.rb b/app/models/artist.rb index 563c36b..3ffafb5 100644 --- a/app/models/artist.rb +++ b/app/models/artist.rb @@ -1,7 +1,7 @@ class Artist < ApplicationRecord has_many :tracks, dependent: :destroy - - validates :name, presence: true + + validates :name, presence: true, uniqueness: true # alpha scope scope :alphabetical, -> { order("LOWER(name) ASC") } diff --git a/app/models/sample.rb b/app/models/sample.rb index f02e6b7..c408e94 100644 --- a/app/models/sample.rb +++ b/app/models/sample.rb @@ -4,6 +4,29 @@ class Sample < ApplicationRecord has_many :sample_segments, dependent: :destroy - # TODO Validate later sampler_entry_id can not be equal sampled_entry_id - # AKA a song can not sample itself or be sampled by itself + validates :derived_track_id, presence: true + validates :source_track_id, presence: true + validate :no_self_sampling + validate :no_sampling_from_future + + + # a source id cannot be equal to a derived id on sample join table + def no_self_sampling + if derived_track_id == source_track_id + errors.add(:base, "A track cannot sample itself") + end + end + + #check sourceYear exist, derivedYear exist, then if derived is less than source throw error + def no_sampling_from_future + if source_track&.year && derived_track&.year && derived_track&.year < source_track&.year + errors.add(:base, "A track cannot sample from the future") + end + end + +#behavior methods +def description + "#{derived_track.title} samples #{source_track.title}" +end + end diff --git a/app/models/track.rb b/app/models/track.rb index 07954bc..2da323a 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -27,6 +27,23 @@ class Track < ApplicationRecord source: :derived_track validates :title, presence: true - validates :year, presence: true + validates :year, numericality: { greater_than_or_equal_to: 1900, less_than_or_equal_to: Date.current.year } validates :bpm, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true + + + #behavior methods + + def formatted_title + "#{title} (#{year})" + end + + def sample_count + samples_used.count + end + + def sampled_by_count + sampled_by_tracks.count +end + + end diff --git a/app/models/user.rb b/app/models/user.rb index ac6aa84..91e74bc 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,10 +1,16 @@ class User < ApplicationRecord has_many :tracks - has_many :comments - # TODO gameplan user.delete, what happens to their entries and comments. + #future nullify user id on orphaned tracks? + has_many :comments, dependent: :destroy has_secure_password + after_initialize :set_default_role, if: :new_record? + + def set_default_role + self.role ||= "user" + end + validates :email, presence: true, uniqueness: true validates :username, presence: true, uniqueness: true diff --git a/app/views/dashboard/index.html.erb b/app/views/dashboard/index.html.erb index 7257866..352fd65 100644 --- a/app/views/dashboard/index.html.erb +++ b/app/views/dashboard/index.html.erb @@ -1,4 +1,9 @@ -

Dashboard

+ +<% if flash[:alert] %> +
+ <%= flash[:alert] %> +
+<% end %>

Recent Tracks

-

- <%= link_to "Add New Track", new_track_path %> -

\ No newline at end of file +
+ <%= link_to "Add New Track", new_track_path, + style: "padding: 10px 20px; background-color: #007bff; color: white; text-decoration: none; border-radius: 5px; margin-right: 10px;" %> + + <%= link_to "Add New Sample Connection", new_sample_path, + style: "padding: 10px 20px; background-color: #28a745; color: white; text-decoration: none; border-radius: 5px; margin-right: 10px;" %> + + <%= link_to "View All Tracks", tracks_path, + style: "padding: 10px 20px; background-color: #6c757d; color: white; text-decoration: none; border-radius: 5px;" %> +
\ No newline at end of file diff --git a/app/views/home/index.html.erb b/app/views/home/index.html.erb new file mode 100644 index 0000000..e48b7e2 --- /dev/null +++ b/app/views/home/index.html.erb @@ -0,0 +1,16 @@ +
+

Sample DB

+

A database of who sampled who.

+
+ + <%= link_to "View All Tracks", tracks_path, class: "btn", + style: "padding: 10px 20px; background-color: #6c757d; color: white; text-decoration: none; border-radius: 5px; margin-right: 10px;" %> + + <%= link_to "Log In", login_path, class: "btn", + style: "padding: 10px 20px; background-color: #007bff; color: white; text-decoration: none; border-radius: 5px; margin-right: 10px;" %> + + <%= link_to "Sign Up", signup_path, class: "btn", + style: "padding: 10px 20px; background-color: #28a745; color: white; text-decoration: none; border-radius: 5px;" %> + +
+
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index d5d1cd2..7be3250 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -22,21 +22,31 @@ <%= javascript_importmap_tags %> - - <% if flash[:notice] %> -

<%= flash[:notice] %>

- <% end %> - - <% if flash[:alert] %> -

<%= flash[:alert] %>

- <% end %> - - <% if logged_in? %> -

Logged in as <%= current_user.username %>

- <%= button_to "Logout", logout_path, method: :delete %> - <% else %> - <%= link_to "Login", login_path %> - <% end %> + +
+
+ +
+ <% if logged_in? %> + <%= button_to "Logout", logout_path, method: :delete %> + <% else %> + <%= link_to "Login", login_path %> + <% end %> +
+ + +
+ <% if logged_in? %> +

Logged in as <%= current_user.username %>

+ <% end %> +
+ + +
+ <%= link_to "Dashboard", dashboard_path %> +
+
+
<%= yield %> diff --git a/app/views/samples/new.html.erb b/app/views/samples/new.html.erb new file mode 100644 index 0000000..d5e9737 --- /dev/null +++ b/app/views/samples/new.html.erb @@ -0,0 +1,27 @@ +

Add Sample Connection

+ +<%= form_with model: @sample, local: true do |f| %> + <% if @sample.errors.any? %> +
+ +
+ <% end %> + +
+
+ <%= f.label :derived_track_id, "New Track" %>
+ <%= f.collection_select :derived_track_id, @tracks, :id, :title, prompt: "Select sampler" %> +
+ +
+ <%= f.label :source_track_id, "Original Source" %>
+ <%= f.collection_select :source_track_id, @tracks, :id, :title, prompt: "Select sampled track" %> +
+
+ + <%= f.submit "Create Sample Connection" %> +<% end %> \ No newline at end of file diff --git a/app/views/sessions/new.html.erb b/app/views/sessions/new.html.erb index 0fa8185..fe59994 100644 --- a/app/views/sessions/new.html.erb +++ b/app/views/sessions/new.html.erb @@ -1,17 +1,24 @@ -

Login

+
+

Log In

-<%= form_with url: login_path, local: true do |form| %> -
- <%= form.label :username %>
- <%= form.text_field :username %> -
- -
- <%= form.label :password %>
- <%= form.password_field :password %> -
+ <%= form_with url: login_path, local: true do |form| %> -
- <%= form.submit "Login" %> + <% if flash[:alert] %> +
+

<%= flash[:alert] %>

<% end %> + +
+ <%= form.label :username %>
+ <%= form.text_field :username %> +
+ +
+ <%= form.label :password %>
+ <%= form.password_field :password %> +
+ + <%= form.submit "Log In", class: "btn btn-primary" %> + <% end %> +
diff --git a/app/views/tracks/show.html.erb b/app/views/tracks/show.html.erb index 0b15a5d..15a77a5 100644 --- a/app/views/tracks/show.html.erb +++ b/app/views/tracks/show.html.erb @@ -1,45 +1,68 @@ -

Track: <%= @track.title %>

+

<%= @track.formatted_title %>

+

- Artist: <%= @track.artist.name %>
- Year: <%= @track.year %>
- BPM: <%= @track.bpm %> + Artist: <%= link_to @track.artist.name, artist_path(@track.artist) %>
+ Added by: <%= @track.user.username %>
+ BPM: <%= @track.bpm || "N/A" %>
+ KEY: <%= @track.key || "N/A" %>
+ Samples used: <%= @track.sample_count %>
+ Sampled by others: <%= @track.sampled_by_count %> +

-

Samples Used

+
+

Samples Used

<% if @track.sampled_tracks.any? %> <% else %>

None

-<% end %> +<% end %> -

Sampled By

+
+

Sampled By

<% if @track.sampled_by_tracks.any? %> <% else %>

None

-<% end %> +<% end %> + +

Comments

- +<% if @track.comments.any? %> + +<% else %> +

No comments yet.

+<% end %> -

- <%= link_to "Edit Track", edit_track_path(@track) %> | - <%= link_to "Delete Track", track_path(@track), - data: { turbo_method: :delete, turbo_confirm: "Are you sure you want to delete this track?" } %> -

\ No newline at end of file +
+ +<% if logged_in? %> +

+ <%= link_to "Edit Track", edit_track_path(@track) %> | + <% if current_user.role == "admin" %> + <%= link_to "Delete Track", track_path(@track), + data: { turbo_method: :delete, turbo_confirm: "Are you sure?" } %> + <% end %> +

+<% end %> \ No newline at end of file diff --git a/app/views/users/create.html.erb b/app/views/users/create.html.erb new file mode 100644 index 0000000..48ea02e --- /dev/null +++ b/app/views/users/create.html.erb @@ -0,0 +1,2 @@ +

Users#create

+

Find me in app/views/users/create.html.erb

diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb new file mode 100644 index 0000000..4fce5fa --- /dev/null +++ b/app/views/users/new.html.erb @@ -0,0 +1,38 @@ +
+

Sign Up

+ +<% if @user.errors.any? %> +
+

<%= pluralize(@user.errors.count, "error") %> prevented sign up:

+
    + <% @user.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+<% end %> + + <%= form_with model: @user, url: signup_path, local: true do |form| %> +
+ <%= form.label :username %>
+ <%= form.text_field :username %> +
+ +
+ <%= form.label :email %>
+ <%= form.email_field :email %> +
+ +
+ <%= form.label :password %>
+ <%= form.password_field :password %> +
+ +
+ <%= form.label :password_confirmation %>
+ <%= form.password_field :password_confirmation %> +
+ + <%= form.submit "Create Account", class: "btn btn-primary" %> + <% end %> +
\ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 06d2d06..1f59293 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,9 +1,14 @@ Rails.application.routes.draw do + get "users/new" + get "users/create" + get "home/index" resources :artists, only: [ :index, :show, :new, :create ] resources :tracks, only: [ :index, :show, :new, :create, :edit, :update, :destroy ] - + resources :samples, only: [:new, :create] + get "/dashboard", to: "dashboard#index" - + get "signup", to: "users#new" + post "signup", to: "users#create" # session routes get "login", to: "sessions#new" post "login", to: "sessions#create" @@ -13,5 +18,5 @@ get "up" => "rails/health#show", as: :rails_health_check # ("/") makes root dashboard - root "dashboard#index" + root "home#index" end diff --git a/db/migrate/20251021021206_add_null_constraint_to_password_digest.rb b/db/migrate/20251021021206_add_null_constraint_to_password_digest.rb new file mode 100644 index 0000000..92fda99 --- /dev/null +++ b/db/migrate/20251021021206_add_null_constraint_to_password_digest.rb @@ -0,0 +1,5 @@ +class AddNullConstraintToPasswordDigest < ActiveRecord::Migration[8.0] + def change + change_column_null :users, :password_digest, false + end +end \ No newline at end of file diff --git a/db/migrate/20251021021407_add_unique_index_to_artists_name.rb b/db/migrate/20251021021407_add_unique_index_to_artists_name.rb new file mode 100644 index 0000000..29de665 --- /dev/null +++ b/db/migrate/20251021021407_add_unique_index_to_artists_name.rb @@ -0,0 +1,6 @@ +class AddUniqueIndexToArtistsName < ActiveRecord::Migration[8.0] + def change + remove_index :artists, :name if index_exists?(:artists, :name) + add_index :artists, :name, unique: true + end +end \ No newline at end of file diff --git a/db/schema.rb b/db/schema.rb index 6b9d551..e7acd3a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,12 +10,12 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.0].define(version: 2025_10_07_214251) do +ActiveRecord::Schema[8.0].define(version: 2025_10_21_021407) do create_table "artists", force: :cascade do |t| t.string "name", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.index ["name"], name: "index_artists_on_name" + t.index ["name"], name: "index_artists_on_name", unique: true end create_table "comments", force: :cascade do |t| @@ -67,7 +67,7 @@ t.string "username", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.string "password_digest" + t.string "password_digest", null: false t.string "role", default: "user", null: false t.index ["email"], name: "index_users_on_email", unique: true t.index ["username"], name: "index_users_on_username", unique: true diff --git a/spec/helpers/home_helper_spec.rb b/spec/helpers/home_helper_spec.rb new file mode 100644 index 0000000..e537d8d --- /dev/null +++ b/spec/helpers/home_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the HomeHelper. For example: +# +# describe HomeHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe HomeHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb new file mode 100644 index 0000000..b2e3444 --- /dev/null +++ b/spec/helpers/users_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the UsersHelper. For example: +# +# describe UsersHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe UsersHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/sample_spec.rb b/spec/models/sample_spec.rb new file mode 100644 index 0000000..40e7c74 --- /dev/null +++ b/spec/models/sample_spec.rb @@ -0,0 +1,30 @@ +require "rails_helper" + +RSpec.describe Sample, type: :model do + let(:artist) { Artist.create!(name: "Test Artist") } + let(:user) { User.create!(username: "tester", email: "t@mail.com", password: "password") } + let(:source) { Track.create!(title: "Original", year: 1990, artist: artist, user: user) } + let(:derived) { Track.create!(title: "Remix", year: 1995, artist: artist, user: user) } + + it "is valid with valid attributes" do + sample = Sample.new(source_track: source, derived_track: derived) + expect(sample).to be_valid + end + + it "is invalid when a track samples itself" do + sample = Sample.new(source_track: source, derived_track: source) + expect(sample).not_to be_valid + expect(sample.errors[:base]).to include("A track cannot sample itself") + end + + it "is invalid when sampling from the future" do + sample = Sample.new(source_track: derived, derived_track: source) + expect(sample).not_to be_valid + expect(sample.errors[:base]).to include("A track cannot sample from the future") + end + + it "returns a readable description" do + sample = Sample.new(source_track: source, derived_track: derived) + expect(sample.description).to eq("Remix samples Original") + end +end \ No newline at end of file diff --git a/spec/requests/dashboard_spec.rb b/spec/requests/dashboard_spec.rb new file mode 100644 index 0000000..eef30f7 --- /dev/null +++ b/spec/requests/dashboard_spec.rb @@ -0,0 +1,9 @@ +require "rails_helper" + +RSpec.describe "Dashboard", type: :request do + it "renders succesfully" do + get "/dashboard" + expect(response).to have_http_status(:ok) + expect(response.body).to include("Track").or include("Dashboard") + end +end \ No newline at end of file diff --git a/spec/requests/home_spec.rb b/spec/requests/home_spec.rb new file mode 100644 index 0000000..fdbd642 --- /dev/null +++ b/spec/requests/home_spec.rb @@ -0,0 +1,11 @@ +require 'rails_helper' + +RSpec.describe "Homes", type: :request do + describe "GET /index" do + it "returns http success" do + get "/home/index" + expect(response).to have_http_status(:success) + end + end + +end diff --git a/spec/requests/users_spec.rb b/spec/requests/users_spec.rb new file mode 100644 index 0000000..550ddac --- /dev/null +++ b/spec/requests/users_spec.rb @@ -0,0 +1,18 @@ +require 'rails_helper' + +RSpec.describe "Users", type: :request do + describe "GET /new" do + it "returns http success" do + get "/users/new" + expect(response).to have_http_status(:success) + end + end + + describe "GET /create" do + it "returns http success" do + get "/users/create" + expect(response).to have_http_status(:success) + end + end + +end diff --git a/spec/views/home/index.html.erb_spec.rb b/spec/views/home/index.html.erb_spec.rb new file mode 100644 index 0000000..75bb045 --- /dev/null +++ b/spec/views/home/index.html.erb_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe "home/index.html.erb", type: :view do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/users/create.html.erb_spec.rb b/spec/views/users/create.html.erb_spec.rb new file mode 100644 index 0000000..e3141c5 --- /dev/null +++ b/spec/views/users/create.html.erb_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe "users/create.html.erb", type: :view do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/views/users/new.html.erb_spec.rb b/spec/views/users/new.html.erb_spec.rb new file mode 100644 index 0000000..47b47d3 --- /dev/null +++ b/spec/views/users/new.html.erb_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe "users/new.html.erb", type: :view do + pending "add some examples to (or delete) #{__FILE__}" +end From 79a9a6d3d1d9aed214396fe3dc9494af98cc945f Mon Sep 17 00:00:00 2001 From: Tristan Date: Tue, 21 Oct 2025 22:34:15 -0400 Subject: [PATCH 2/4] format --- app/controllers/dashboard_controller.rb | 10 ++-- app/controllers/samples_controller.rb | 32 ++++++------- app/controllers/sessions_controller.rb | 1 - app/controllers/tracks_controller.rb | 10 ++-- app/controllers/users_controller.rb | 8 ++-- app/models/artist.rb | 2 +- app/models/sample.rb | 14 +++--- app/models/track.rb | 13 ++--- app/models/user.rb | 2 +- config/routes.rb | 4 +- ..._add_null_constraint_to_password_digest.rb | 2 +- ...021407_add_unique_index_to_artists_name.rb | 2 +- spec/helpers/home_helper_spec.rb | 2 +- spec/helpers/users_helper_spec.rb | 2 +- spec/models/sample_spec.rb | 48 +++++++++---------- spec/requests/dashboard_spec.rb | 14 +++--- spec/requests/home_spec.rb | 3 +- spec/requests/users_spec.rb | 3 +- spec/views/home/index.html.erb_spec.rb | 2 +- spec/views/users/create.html.erb_spec.rb | 2 +- spec/views/users/new.html.erb_spec.rb | 2 +- 21 files changed, 85 insertions(+), 93 deletions(-) diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 28dc6cf..863cf28 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -8,10 +8,10 @@ def index private - def require_login - unless logged_in? - flash[:alert] = "Please log in to access the dashboard" - redirect_to login_path + def require_login + unless logged_in? + flash[:alert] = "Please log in to access the dashboard" + redirect_to login_path + end end - end end diff --git a/app/controllers/samples_controller.rb b/app/controllers/samples_controller.rb index 6cc3878..2954d0d 100644 --- a/app/controllers/samples_controller.rb +++ b/app/controllers/samples_controller.rb @@ -1,24 +1,24 @@ class SamplesController < ApplicationController - before_action :require_admin + before_action :require_admin - def new - @sample = Sample.new - @tracks = Track.order(:title) - end + def new + @sample = Sample.new + @tracks = Track.order(:title) + end - def create - @sample = Sample.new(sample_params) - if @sample.save - redirect_to dashboard_path, notice: "Sample Connection created!" - else - @tracks = Track.order(:title) - render :new, status: :unprocessable_entity - end + def create + @sample = Sample.new(sample_params) + if @sample.save + redirect_to dashboard_path, notice: "Sample Connection created!" + else + @tracks = Track.order(:title) + render :new, status: :unprocessable_entity end + end private - def sample_params + def sample_params params.require(:sample).permit(:derived_track_id, :source_track_id) - end -end \ No newline at end of file + end +end diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index 7dc2135..c7341f0 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -6,7 +6,6 @@ def new def create user = User.find_by(username: params[:username]) - if user&.authenticate(params[:password]) session[:user_id] = user.id session[:role] = user.role diff --git a/app/controllers/tracks_controller.rb b/app/controllers/tracks_controller.rb index 3b68ac8..6268b16 100644 --- a/app/controllers/tracks_controller.rb +++ b/app/controllers/tracks_controller.rb @@ -23,15 +23,15 @@ def create if @track.save redirect_to @track, notice: "Track Created!" else - @artists = Artist.alphabetical + @artists = Artist.alphabetical render :new, status: :unprocessable_entity end end -def edit - @track = Track.find(params[:id]) - @artists = Artist.alphabetical -end + def edit + @track = Track.find(params[:id]) + @artists = Artist.alphabetical + end def update @track = Track.find(params[:id]) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 0d68b77..7f25bb4 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -16,7 +16,7 @@ def create private - def user_params - params.require(:user).permit(:username, :email, :password, :password_confirmation) - end -end \ No newline at end of file + def user_params + params.require(:user).permit(:username, :email, :password, :password_confirmation) + end +end diff --git a/app/models/artist.rb b/app/models/artist.rb index 3ffafb5..cce7283 100644 --- a/app/models/artist.rb +++ b/app/models/artist.rb @@ -1,6 +1,6 @@ class Artist < ApplicationRecord has_many :tracks, dependent: :destroy - + validates :name, presence: true, uniqueness: true # alpha scope diff --git a/app/models/sample.rb b/app/models/sample.rb index c408e94..b3d350b 100644 --- a/app/models/sample.rb +++ b/app/models/sample.rb @@ -9,24 +9,22 @@ class Sample < ApplicationRecord validate :no_self_sampling validate :no_sampling_from_future - # a source id cannot be equal to a derived id on sample join table def no_self_sampling if derived_track_id == source_track_id errors.add(:base, "A track cannot sample itself") end end - - #check sourceYear exist, derivedYear exist, then if derived is less than source throw error + + # check sourceYear exist, derivedYear exist, then if derived is less than source throw error def no_sampling_from_future if source_track&.year && derived_track&.year && derived_track&.year < source_track&.year errors.add(:base, "A track cannot sample from the future") end end -#behavior methods -def description - "#{derived_track.title} samples #{source_track.title}" -end - + # behavior methods + def description + "#{derived_track.title} samples #{source_track.title}" + end end diff --git a/app/models/track.rb b/app/models/track.rb index 2da323a..41c8099 100644 --- a/app/models/track.rb +++ b/app/models/track.rb @@ -30,20 +30,17 @@ class Track < ApplicationRecord validates :year, numericality: { greater_than_or_equal_to: 1900, less_than_or_equal_to: Date.current.year } validates :bpm, numericality: { greater_than_or_equal_to: 0 }, allow_nil: true + # behavior methods - #behavior methods - - def formatted_title + def formatted_title "#{title} (#{year})" - end +end def sample_count samples_used.count end - + def sampled_by_count - sampled_by_tracks.count + sampled_by_tracks.count end - - end diff --git a/app/models/user.rb b/app/models/user.rb index 91e74bc..f1bac00 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,6 +1,6 @@ class User < ApplicationRecord has_many :tracks - #future nullify user id on orphaned tracks? + # future nullify user id on orphaned tracks? has_many :comments, dependent: :destroy has_secure_password diff --git a/config/routes.rb b/config/routes.rb index 1f59293..996ef18 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,8 +4,8 @@ get "home/index" resources :artists, only: [ :index, :show, :new, :create ] resources :tracks, only: [ :index, :show, :new, :create, :edit, :update, :destroy ] - resources :samples, only: [:new, :create] - + resources :samples, only: [ :new, :create ] + get "/dashboard", to: "dashboard#index" get "signup", to: "users#new" post "signup", to: "users#create" diff --git a/db/migrate/20251021021206_add_null_constraint_to_password_digest.rb b/db/migrate/20251021021206_add_null_constraint_to_password_digest.rb index 92fda99..bc373b2 100644 --- a/db/migrate/20251021021206_add_null_constraint_to_password_digest.rb +++ b/db/migrate/20251021021206_add_null_constraint_to_password_digest.rb @@ -2,4 +2,4 @@ class AddNullConstraintToPasswordDigest < ActiveRecord::Migration[8.0] def change change_column_null :users, :password_digest, false end -end \ No newline at end of file +end diff --git a/db/migrate/20251021021407_add_unique_index_to_artists_name.rb b/db/migrate/20251021021407_add_unique_index_to_artists_name.rb index 29de665..ae3f035 100644 --- a/db/migrate/20251021021407_add_unique_index_to_artists_name.rb +++ b/db/migrate/20251021021407_add_unique_index_to_artists_name.rb @@ -3,4 +3,4 @@ def change remove_index :artists, :name if index_exists?(:artists, :name) add_index :artists, :name, unique: true end -end \ No newline at end of file +end diff --git a/spec/helpers/home_helper_spec.rb b/spec/helpers/home_helper_spec.rb index e537d8d..a54e1a1 100644 --- a/spec/helpers/home_helper_spec.rb +++ b/spec/helpers/home_helper_spec.rb @@ -10,6 +10,6 @@ # end # end # end -RSpec.describe HomeHelper, type: :helper do +RSpec.describe HomeHelper do pending "add some examples to (or delete) #{__FILE__}" end diff --git a/spec/helpers/users_helper_spec.rb b/spec/helpers/users_helper_spec.rb index b2e3444..c55ad65 100644 --- a/spec/helpers/users_helper_spec.rb +++ b/spec/helpers/users_helper_spec.rb @@ -10,6 +10,6 @@ # end # end # end -RSpec.describe UsersHelper, type: :helper do +RSpec.describe UsersHelper do pending "add some examples to (or delete) #{__FILE__}" end diff --git a/spec/models/sample_spec.rb b/spec/models/sample_spec.rb index 40e7c74..da996d1 100644 --- a/spec/models/sample_spec.rb +++ b/spec/models/sample_spec.rb @@ -1,30 +1,30 @@ require "rails_helper" -RSpec.describe Sample, type: :model do - let(:artist) { Artist.create!(name: "Test Artist") } - let(:user) { User.create!(username: "tester", email: "t@mail.com", password: "password") } - let(:source) { Track.create!(title: "Original", year: 1990, artist: artist, user: user) } - let(:derived) { Track.create!(title: "Remix", year: 1995, artist: artist, user: user) } +RSpec.describe Sample do + let(:artist) { Artist.create!(name: "Test Artist") } + let(:user) { User.create!(username: "tester", email: "t@mail.com", password: "password") } + let(:source) { Track.create!(title: "Original", year: 1990, artist: artist, user: user) } + let(:derived) { Track.create!(title: "Remix", year: 1995, artist: artist, user: user) } - it "is valid with valid attributes" do - sample = Sample.new(source_track: source, derived_track: derived) - expect(sample).to be_valid - end + it "is valid with valid attributes" do + sample = described_class.new(source_track: source, derived_track: derived) + expect(sample).to be_valid + end - it "is invalid when a track samples itself" do - sample = Sample.new(source_track: source, derived_track: source) - expect(sample).not_to be_valid - expect(sample.errors[:base]).to include("A track cannot sample itself") - end + it "is invalid when a track samples itself" do + sample = described_class.new(source_track: source, derived_track: source) + expect(sample).not_to be_valid + expect(sample.errors[:base]).to include("A track cannot sample itself") + end - it "is invalid when sampling from the future" do - sample = Sample.new(source_track: derived, derived_track: source) - expect(sample).not_to be_valid - expect(sample.errors[:base]).to include("A track cannot sample from the future") - end + it "is invalid when sampling from the future" do + sample = described_class.new(source_track: derived, derived_track: source) + expect(sample).not_to be_valid + expect(sample.errors[:base]).to include("A track cannot sample from the future") + end - it "returns a readable description" do - sample = Sample.new(source_track: source, derived_track: derived) - expect(sample.description).to eq("Remix samples Original") - end -end \ No newline at end of file + it "returns a readable description" do + sample = described_class.new(source_track: source, derived_track: derived) + expect(sample.description).to eq("Remix samples Original") + end +end diff --git a/spec/requests/dashboard_spec.rb b/spec/requests/dashboard_spec.rb index eef30f7..0fcf53a 100644 --- a/spec/requests/dashboard_spec.rb +++ b/spec/requests/dashboard_spec.rb @@ -1,9 +1,9 @@ require "rails_helper" -RSpec.describe "Dashboard", type: :request do - it "renders succesfully" do - get "/dashboard" - expect(response).to have_http_status(:ok) - expect(response.body).to include("Track").or include("Dashboard") - end -end \ No newline at end of file +RSpec.describe "Dashboard" do + it "renders succesfully" do + get "/dashboard" + expect(response).to have_http_status(:ok) + expect(response.body).to include("Track").or include("Dashboard") + end +end diff --git a/spec/requests/home_spec.rb b/spec/requests/home_spec.rb index fdbd642..3d279d2 100644 --- a/spec/requests/home_spec.rb +++ b/spec/requests/home_spec.rb @@ -1,11 +1,10 @@ require 'rails_helper' -RSpec.describe "Homes", type: :request do +RSpec.describe "Homes" do describe "GET /index" do it "returns http success" do get "/home/index" expect(response).to have_http_status(:success) end end - end diff --git a/spec/requests/users_spec.rb b/spec/requests/users_spec.rb index 550ddac..2ecc182 100644 --- a/spec/requests/users_spec.rb +++ b/spec/requests/users_spec.rb @@ -1,6 +1,6 @@ require 'rails_helper' -RSpec.describe "Users", type: :request do +RSpec.describe "Users" do describe "GET /new" do it "returns http success" do get "/users/new" @@ -14,5 +14,4 @@ expect(response).to have_http_status(:success) end end - end diff --git a/spec/views/home/index.html.erb_spec.rb b/spec/views/home/index.html.erb_spec.rb index 75bb045..ea77ece 100644 --- a/spec/views/home/index.html.erb_spec.rb +++ b/spec/views/home/index.html.erb_spec.rb @@ -1,5 +1,5 @@ require 'rails_helper' -RSpec.describe "home/index.html.erb", type: :view do +RSpec.describe "home/index.html.erb" do pending "add some examples to (or delete) #{__FILE__}" end diff --git a/spec/views/users/create.html.erb_spec.rb b/spec/views/users/create.html.erb_spec.rb index e3141c5..738fd62 100644 --- a/spec/views/users/create.html.erb_spec.rb +++ b/spec/views/users/create.html.erb_spec.rb @@ -1,5 +1,5 @@ require 'rails_helper' -RSpec.describe "users/create.html.erb", type: :view do +RSpec.describe "users/create.html.erb" do pending "add some examples to (or delete) #{__FILE__}" end diff --git a/spec/views/users/new.html.erb_spec.rb b/spec/views/users/new.html.erb_spec.rb index 47b47d3..96b161f 100644 --- a/spec/views/users/new.html.erb_spec.rb +++ b/spec/views/users/new.html.erb_spec.rb @@ -1,5 +1,5 @@ require 'rails_helper' -RSpec.describe "users/new.html.erb", type: :view do +RSpec.describe "users/new.html.erb" do pending "add some examples to (or delete) #{__FILE__}" end From a27399933ff0eb0afd04875bef778b279f7c1c55 Mon Sep 17 00:00:00 2001 From: Tristan Date: Wed, 22 Oct 2025 08:34:57 -0400 Subject: [PATCH 3/4] Rspec expectations increaese to 2 --- .rubocop.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.rubocop.yml b/.rubocop.yml index fa6eab6..c575763 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -37,4 +37,7 @@ Layout/TrailingWhitespace: # require exactly one final newline at end of each file Layout/TrailingEmptyLines: - Enabled: true \ No newline at end of file + Enabled: true + +RSpec/MultipleExpectations: + Max: 2 \ No newline at end of file From 47e7739e2ee7b5478406e76420515eb3e752fbaa Mon Sep 17 00:00:00 2001 From: Tristan Date: Wed, 22 Oct 2025 08:58:49 -0400 Subject: [PATCH 4/4] flash alert --- app/views/layouts/application.html.erb | 60 +++++++++++++++----------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 7be3250..69ae419 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -22,32 +22,44 @@ <%= javascript_importmap_tags %> - -
-
- -
- <% if logged_in? %> - <%= button_to "Logout", logout_path, method: :delete %> - <% else %> - <%= link_to "Login", login_path %> - <% end %> -
+ +
+
+ +
+ <% if logged_in? %> + <%= button_to "Logout", logout_path, method: :delete %> + <% else %> + <%= link_to "Login", login_path %> + <% end %> +
+ + +
+ <% if logged_in? %> +

Logged in as <%= current_user.username %>

+ <% end %> +
- -
- <% if logged_in? %> -

Logged in as <%= current_user.username %>

- <% end %> + +
+ <%= link_to "Dashboard", dashboard_path %> +
+
- -
- <%= link_to "Dashboard", dashboard_path %> + <%= yield %> + + <% if flash[:notice] %> +
+ <%= flash[:notice] %>
-
-
+ <% end %> - <%= yield %> - - + <% if flash[:alert] %> +
+ <%= flash[:alert] %> +
+ <% end %> + + \ No newline at end of file