This commit is contained in:
Rikuoh Tsujitani 2024-08-18 22:59:25 +09:00
parent 091bb382c8
commit 081344beae
Signed by: riq0h
GPG key ID: 010F09DEA298C717
9 changed files with 103 additions and 93 deletions

View file

@ -1,9 +1,9 @@
## Usage
`git clone https://github.com/riq0h/memoapp.git`
`cd memoapp`
`bundle install`
`ruby app.rb`
```
git clone https://github.com/riq0h/memoapp.git
cd memoapp
bundle install
psql -U postgres -f memos.sql
ruby app.rb
```

View file

@ -2,29 +2,46 @@
require 'sinatra'
require 'sinatra/reloader'
require 'json'
require 'securerandom'
require 'pg'
require 'cgi'
FILE_PATH = 'memos.json'
configure do
set :conn, PG.connect(dbname: 'memo_app')
end
helpers do
def h(text)
CGI.escapeHTML(text.to_s)
end
end
def load_memos
if !File.zero?(FILE_PATH)
JSON.parse(File.read(FILE_PATH))
else
{}
def db
settings.conn
end
end
def save_memos(memos)
File.open(FILE_PATH, 'w') do |file|
file.write(JSON.generate(memos))
def find_memo(id)
db.exec_params('SELECT * FROM memos WHERE id = $1', [id]).first
end
def create_memo(title, content)
db.exec_params(
'INSERT INTO memos (title, content) VALUES ($1, $2) RETURNING id',
[title, content]
).first['id']
end
def update_memo(id, title, content)
db.exec_params(
'UPDATE memos SET title = $1, content = $2 WHERE id = $3',
[title, content, id]
)
end
def delete_memo(id)
db.exec_params('DELETE FROM memos WHERE id = $1', [id])
end
def all_memos
db.exec('SELECT * FROM memos ORDER BY created_at DESC').to_a
end
end
@ -33,7 +50,7 @@ get '/' do
end
get '/memos' do
@memos = load_memos
@memos = all_memos
erb :index
end
@ -42,37 +59,29 @@ get '/memos/new' do
end
post '/memos' do
memos = load_memos
id = SecureRandom.uuid
memos[id] = { 'title' => params[:title], 'content' => params[:content] }
save_memos(memos)
redirect '/memos'
id = create_memo(params[:title], params[:content])
redirect "/memos/#{id}"
end
get '/memos/:id' do
@memo = load_memos[params[:id]]
@memo = find_memo(params[:id])
halt 404, erb(:not_found) unless @memo
erb :show
end
get '/memos/:id/edit' do
@memo = load_memos[params[:id]]
@memo = find_memo(params[:id])
halt 404, erb(:not_found) unless @memo
erb :edit
end
patch '/memos/:id' do
memos = load_memos
halt 404, erb(:not_found) unless memos[params[:id]]
memos[params[:id]] = { 'title' => params[:title], 'content' => params[:content] }
save_memos(memos)
update_memo(params[:id], params[:title], params[:content])
redirect "/memos/#{params[:id]}"
end
delete '/memos/:id' do
memos = load_memos
halt 404, erb(:not_found) unless memos.delete(params[:id])
save_memos(memos)
delete_memo(params[:id])
redirect '/memos'
end

9
memoapp/memos.sql Normal file
View file

@ -0,0 +1,9 @@
CREATE DATABASE memo_app;
DROP TABLE IF EXISTS memos;
\c memo_app
CREATE TABLE memos (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

View file

@ -1,3 +1,10 @@
:root {
--save-color: #007bff;
--edit-color: #28a745;
--delete-color: #dc3545;
--back-color: #6c757d;
}
body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
@ -35,7 +42,7 @@ nav {
nav a {
margin: 0 10px;
text-decoration: none;
color: #007bff;
color: var(--save-color);
}
nav a:hover {
@ -59,44 +66,42 @@ form textarea {
border-radius: 4px;
}
form button {
.button {
padding: 10px;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
text-decoration: none;
text-align: center;
display: inline-block;
width: 100%;
}
form button.save {
background-color: #007bff;
.button:hover {
opacity: 0.9;
}
form button.save:hover {
background-color: #0056b3;
.button.save {
background-color: var(--save-color);
}
form button.delete {
background-color: #dc3545;
.button.delete {
background-color: var(--delete-color);
padding: 12px;
font-size: 90%;
}
form button.delete:hover {
background-color: #c82333;
.button.edit {
background-color: var(--edit-color);
}
form button.edit {
background-color: #28a745;
}
form button.edit:hover {
background-color: #218838;
}
form button.back {
background-color: #6c757d;
}
form button.back:hover {
background-color: #5a6268;
.button.back {
background-color: var(--back-color);
margin-top: 10px;
display: block;
margin: 10px auto 0;
box-sizing: border-box;
}
.memo-list {
@ -110,7 +115,7 @@ form button.back:hover {
.memo-list a {
text-decoration: none;
color: #007bff;
color: var(--save-color);
}
.memo-list a:hover {
@ -123,27 +128,18 @@ form button.back:hover {
margin-bottom: 10px;
}
.memo-actions form {
display: inline;
.memo-actions form,
.memo-actions a {
flex: 1;
margin: 0 5px;
}
.memo-actions button {
padding: 10px;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
.memo-actions form:first-child,
.memo-actions a:first-child {
margin-left: 0;
}
.memo-actions .edit {
background-color: #28a745;
.memo-actions form:last-child,
.memo-actions a:last-child {
margin-right: 0;
}
.memo-actions .edit:hover {
background-color: #218838;
}
.memo-actions .back {
background-color: #6c757d;
}

View file

@ -1,8 +1,8 @@
<form action="/memos/<%= params[:id] %>" method="post">
<form action="/memos/<%= @memo['id'] %>" method="post">
<input type="hidden" name="_method" value="patch">
<label for="title">タイトル</label>
<input type="text" name="title" id="title" value="<%= h(@memo['title']) %>">
<label for="content">内容</label>
<textarea name="content" id="content"><%= h(@memo['content']) %></textarea>
<button type="submit" class="edit">変更</button>
<button type="submit" class="button save">保存</button>
</form>

View file

@ -1,5 +1,5 @@
<ul class="memo-list">
<% @memos.each do |id, memo| %>
<li><a href="/memos/<%= id %>"><%= h(memo["title"]) %></a></li>
<% @memos.each do |memo| %>
<li><a href="/memos/<%= memo['id'] %>"><%= h(memo['title']) %></a></li>
<% end %>
</ul>

View file

@ -3,5 +3,5 @@
<input type="text" name="title" id="title">
<label for="content">内容</label>
<textarea name="content" id="content"></textarea>
<button type="submit" class="save">保存</button>
<button type="submit" class="button save">保存</button>
</form>

View file

@ -1,3 +1,3 @@
<h1>404 Not Found</h1>
<h2>404 Not Found</h2>
<p>お探しのページは見つかりませんでした。</p>
<a href="/">トップページに戻る</a>

View file

@ -1,14 +1,10 @@
<h2><%= h(@memo['title']) %></h2>
<p><%= h(@memo['content']) %></p>
<div class="memo-actions">
<form action="/memos/<%= params[:id] %>/edit" method="get">
<button type="submit" class="edit">変更</button>
</form>
<form action="/memos/<%= params[:id] %>" method="post">
<a href="/memos/<%= @memo['id'] %>/edit" class="button edit">編集</a>
<form action="/memos/<%= @memo['id'] %>" method="post">
<input type="hidden" name="_method" value="delete">
<button type="submit" class="delete">削除</button>
<button type="submit" class="button delete">削除</button>
</form>
</div>
<form action="/memos" method="get">
<button type="submit" class="back">戻る</button>
</form>
<a href="/memos" class="button back">戻る</a>