Skip to content

Commit 20c3eee

Browse files
[#27] Create folder model and controller (#46)
* [#27] Create folder model and controller * Add slugs to folders
1 parent 57a54e1 commit 20c3eee

15 files changed

Lines changed: 265 additions & 4 deletions
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
class FoldersController < ApplicationController
2+
# before_action :authenticate_user!, except: [:index, :show]
3+
before_action :authenticate_user!, only: [ :my_folders ] # temporary until users
4+
before_action :authorize_user!, only: [ :update, :destroy ]
5+
6+
7+
# GET /folders
8+
def index
9+
folders = Folder.all
10+
render json: FolderSerializer.new(folders).serializable_hash.to_json
11+
end
12+
13+
# GET /my_folders
14+
def my_folders
15+
folders = current_user.folders
16+
render json: FolderSerializer.new(folders).serializable_hash.to_json
17+
end
18+
19+
# GET /folders/:id
20+
def show
21+
render json: FolderSerializer.new(folder).serializable_hash.to_json
22+
end
23+
24+
# POST /folders
25+
def create
26+
folder = Folder.new(folder_params)
27+
folder.user = current_user if user_signed_in?
28+
29+
if folder.save
30+
render json: FolderSerializer.new(folder).serializable_hash.to_json, status: :created
31+
else
32+
render json: { errors: folder.errors.full_messages }, status: :unprocessable_entity
33+
end
34+
end
35+
36+
# PATCH /folders/:id
37+
def update
38+
if folder.update(folder_params)
39+
render json: FolderSerializer.new(folder).serializable_hash.to_json
40+
else
41+
render json: { errors: folder.errors.full_messages }, status: :unprocessable_entity
42+
end
43+
end
44+
45+
# DELETE /folders/:id
46+
def destroy
47+
folder.destroy
48+
head :no_content
49+
end
50+
51+
private
52+
53+
def folder
54+
@folder ||= Folder.find(params[:id])
55+
end
56+
57+
def folder_params
58+
params.require(:folder).permit(:name, :slug, sound_ids: [])
59+
end
60+
61+
def authorize_user!
62+
if folder.user.present? && folder.user != current_user
63+
render json: { error: "Not authorized" }, status: :forbidden
64+
end
65+
end
66+
end

api/app/controllers/sounds_controller.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ def index
88
end
99

1010
def my_sounds
11-
authenticate_user!
1211
sounds = current_user.sounds
1312
render json: SoundSerializer.new(sounds).serializable_hash.to_json
1413
end

api/app/models/folder.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
class Folder < ApplicationRecord
2+
belongs_to :user, optional: true
3+
has_and_belongs_to_many :sounds
4+
5+
before_validation :set_slug, on: [ :create, :update ]
6+
7+
validates :name, presence: true
8+
9+
private
10+
11+
def set_slug
12+
base_slug = name.parameterize
13+
candidate = base_slug
14+
count = 2
15+
16+
while Folder.exists?(slug: candidate)
17+
candidate = "#{base_slug}-#{count}"
18+
count += 1
19+
end
20+
21+
self.slug = candidate
22+
end
23+
end

api/app/models/sound.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
class Sound < ApplicationRecord
22
has_and_belongs_to_many :tags
3+
has_and_belongs_to_many :folders
34
has_one_attached :audio_file
45
belongs_to :user, optional: true
56

api/app/models/user.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ class User < ApplicationRecord
66
validates :email, presence: true, uniqueness: true
77
validates :username, presence: true, uniqueness: true
88
has_many :sounds
9+
has_many :folders
910
end
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
class FolderSerializer
2+
include JSONAPI::Serializer
3+
attributes :name, :slug
4+
5+
attribute :sounds do |object|
6+
object.sounds.map do |sound|
7+
{
8+
id: sound.id,
9+
name: sound.name,
10+
user_id: sound.user_id,
11+
color: sound.color,
12+
emoji: sound.emoji,
13+
audio_file_url: (Rails.application.routes.url_helpers.rails_blob_url(sound.audio_file, only_path: true) if sound.audio_file.attached?),
14+
tags: sound.tags.map { |tag| { id: tag.id, name: tag.name, color: tag.color } }
15+
}
16+
end
17+
end
18+
end

api/app/serializers/sound_serializer.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@ class SoundSerializer
88
end
99
end
1010
attribute :tags do |object|
11-
object.tags.map { |tag| { id: tag.id, name: tag.name } }
11+
object.tags.map { |tag| { id: tag.id, name: tag.name, color: tag.color } }
1212
end
1313
end

api/config/routes.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
get "my_sounds", to: "sounds#my_sounds"
1313

1414
resources :tags
15+
resources :folders
16+
get "my_folders", to: "folders#my_folders"
1517
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
1618

1719
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
class CreateFoldersTable < ActiveRecord::Migration[8.0]
2+
def change
3+
create_table :folders do |t|
4+
t.string :name, null: false
5+
t.references :user, foreign_key: true, null: true
6+
t.timestamps
7+
end
8+
end
9+
end
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
class CreateJoinTableFoldersSounds < ActiveRecord::Migration[8.0]
2+
def change
3+
create_table :folders_sounds, id: false do |t|
4+
t.references :folder, null: false, foreign_key: true
5+
t.references :sound, null: false, foreign_key: true
6+
end
7+
8+
add_index :folders_sounds, [ :folder_id, :sound_id ], unique: true
9+
end
10+
end

0 commit comments

Comments
 (0)