diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 0000000..2f1084d --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,70 @@ +class UsersController < ApplicationController + before_action :set_user, only: %i[ show edit update destroy ] + + # GET /users or /users.json + def index + @users = User.all + end + + # GET /users/1 or /users/1.json + def show + end + + # GET /users/new + def new + @user = User.new + end + + # GET /users/1/edit + def edit + end + + # POST /users or /users.json + def create + @user = User.new(user_params) + + respond_to do |format| + if @user.save + format.html { redirect_to user_url(@user), notice: "User was successfully created." } + format.json { render :show, status: :created, location: @user } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @user.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /users/1 or /users/1.json + def update + respond_to do |format| + if @user.update(user_params) + format.html { redirect_to user_url(@user), notice: "User was successfully updated." } + format.json { render :show, status: :ok, location: @user } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @user.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /users/1 or /users/1.json + def destroy + @user.destroy! + + respond_to do |format| + format.html { redirect_to users_url, notice: "User was successfully destroyed." } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_user + @user = User.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def user_params + params.require(:user).permit(:email, :password, :password_confirmation) + end +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/user.rb b/app/models/user.rb new file mode 100644 index 0000000..d67da20 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,3 @@ +class User < ApplicationRecord + has_secure_password +end diff --git a/app/views/users/_form.html.erb b/app/views/users/_form.html.erb new file mode 100644 index 0000000..5ea1ca7 --- /dev/null +++ b/app/views/users/_form.html.erb @@ -0,0 +1,32 @@ +<%= form_with(model: user, class: "contents") do |form| %> + <% if user.errors.any? %> +
+

<%= pluralize(user.errors.count, "error") %> prohibited this user from being saved:

+ + +
+ <% end %> + +
+ <%= form.label :email %> + <%= form.text_field :email, class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %> +
+ +
+ <%= form.label :password %> + <%= form.password_field :password, class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %> +
+ +
+ <%= form.label :password_confirmation %> + <%= form.password_field :password_confirmation, class: "block shadow rounded-md border border-gray-400 outline-none px-3 py-2 mt-2 w-full" %> +
+ +
+ <%= form.submit class: "rounded-lg py-3 px-5 bg-blue-600 text-white inline-block font-medium cursor-pointer" %> +
+<% end %> diff --git a/app/views/users/_user.html.erb b/app/views/users/_user.html.erb new file mode 100644 index 0000000..8c202c1 --- /dev/null +++ b/app/views/users/_user.html.erb @@ -0,0 +1,7 @@ +
+

+ Email: + <%= user.email %> +

+ +
diff --git a/app/views/users/_user.json.jbuilder b/app/views/users/_user.json.jbuilder new file mode 100644 index 0000000..8b12e34 --- /dev/null +++ b/app/views/users/_user.json.jbuilder @@ -0,0 +1,2 @@ +json.extract! user, :id, :email, :created_at, :updated_at +json.url user_url(user, format: :json) diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb new file mode 100644 index 0000000..e700c3e --- /dev/null +++ b/app/views/users/edit.html.erb @@ -0,0 +1,8 @@ +
+

Editing user

+ + <%= render "form", user: @user %> + + <%= link_to "Show this user", @user, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %> + <%= link_to "Back to users", users_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %> +
diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb new file mode 100644 index 0000000..ee6f295 --- /dev/null +++ b/app/views/users/index.html.erb @@ -0,0 +1,21 @@ +
+ <% if notice.present? %> +

<%= notice %>

+ <% end %> + + <% content_for :title, "Users" %> + +
+

Users

+ <%= link_to "New user", new_user_path, class: "rounded-lg py-3 px-5 bg-blue-600 text-white block font-medium" %> +
+ +
+ <% @users.each do |user| %> + <%= render user %> +

+ <%= link_to "Show this user", user, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %> +

+ <% end %> +
+
diff --git a/app/views/users/index.json.jbuilder b/app/views/users/index.json.jbuilder new file mode 100644 index 0000000..98788da --- /dev/null +++ b/app/views/users/index.json.jbuilder @@ -0,0 +1 @@ +json.array! @users, partial: "users/user", as: :user diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb new file mode 100644 index 0000000..ea5b08d --- /dev/null +++ b/app/views/users/new.html.erb @@ -0,0 +1,7 @@ +
+

New user

+ + <%= render "form", user: @user %> + + <%= link_to "Back to users", users_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %> +
diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb new file mode 100644 index 0000000..8e2d55c --- /dev/null +++ b/app/views/users/show.html.erb @@ -0,0 +1,15 @@ +
+
+ <% if notice.present? %> +

<%= notice %>

+ <% end %> + + <%= render @user %> + + <%= link_to "Edit this user", edit_user_path(@user), class: "mt-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %> + <%= link_to "Back to users", users_path, class: "ml-2 rounded-lg py-3 px-5 bg-gray-100 inline-block font-medium" %> +
+ <%= button_to "Destroy this user", @user, method: :delete, class: "mt-2 rounded-lg py-3 px-5 bg-gray-100 font-medium" %> +
+
+
diff --git a/app/views/users/show.json.jbuilder b/app/views/users/show.json.jbuilder new file mode 100644 index 0000000..ff40bb9 --- /dev/null +++ b/app/views/users/show.json.jbuilder @@ -0,0 +1 @@ +json.partial! "users/user", user: @user diff --git a/config/routes.rb b/config/routes.rb index 4930193..74d76c3 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ Rails.application.routes.draw do + resources :users resources :credit_card_bills resource :dashboard, only: :show resources :incomes diff --git a/db/migrate/20240727022931_create_users.rb b/db/migrate/20240727022931_create_users.rb new file mode 100644 index 0000000..f077285 --- /dev/null +++ b/db/migrate/20240727022931_create_users.rb @@ -0,0 +1,11 @@ +class CreateUsers < ActiveRecord::Migration[8.0] + def change + create_table :users do |t| + t.string :email + t.string :password_digest + + t.timestamps + end + add_index :users, :email, unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index d134a4c..a8caf00 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[8.0].define(version: 2024_07_27_002531) do +ActiveRecord::Schema[8.0].define(version: 2024_07_27_022931) do create_table "credit_card_bills", force: :cascade do |t| t.string "description" t.decimal "amount" @@ -148,6 +148,14 @@ ActiveRecord::Schema[8.0].define(version: 2024_07_27_002531) do t.index ["key"], name: "index_solid_queue_semaphores_on_key", unique: true end + create_table "users", force: :cascade do |t| + t.string "email" + t.string "password_digest" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["email"], name: "index_users_on_email", unique: true + end + add_foreign_key "incomes", "members" add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade diff --git a/test/controllers/users_controller_test.rb b/test/controllers/users_controller_test.rb new file mode 100644 index 0000000..71dd43d --- /dev/null +++ b/test/controllers/users_controller_test.rb @@ -0,0 +1,55 @@ +require "test_helper" + +class UsersControllerTest < ActionDispatch::IntegrationTest + setup do + @user = users(:one) + end + + test "should get index" do + get users_url + assert_response :success + end + + test "should get new" do + get new_user_url + assert_response :success + end + + test "should create user" do + assert_difference("User.count") do + params = { + user: { + email: "userthree@example.local", + password: "secret", + password_confirmation: "secret" + } + } + post users_url, params: params + end + + assert_redirected_to user_url(User.last) + end + + test "should show user" do + get user_url(@user) + assert_response :success + end + + test "should get edit" do + get edit_user_url(@user) + assert_response :success + end + + test "should update user" do + patch user_url(@user), params: { user: { email: @user.email, password: "secret", password_confirmation: "secret" } } + assert_redirected_to user_url(@user) + end + + test "should destroy user" do + assert_difference("User.count", -1) do + delete user_url(@user) + end + + assert_redirected_to users_url + end +end diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml new file mode 100644 index 0000000..99db479 --- /dev/null +++ b/test/fixtures/users.yml @@ -0,0 +1,9 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + email: userone@example.local + password_digest: <%= BCrypt::Password.create("secret") %> + +two: + email: usertwo@example.local + password_digest: <%= BCrypt::Password.create("secret") %> diff --git a/test/models/user_test.rb b/test/models/user_test.rb new file mode 100644 index 0000000..5c07f49 --- /dev/null +++ b/test/models/user_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/system/users_test.rb b/test/system/users_test.rb new file mode 100644 index 0000000..00e5e87 --- /dev/null +++ b/test/system/users_test.rb @@ -0,0 +1,45 @@ +require "application_system_test_case" + +class UsersTest < ApplicationSystemTestCase + setup do + @user = users(:one) + end + + test "visiting the index" do + visit users_url + assert_selector "h1", text: "Users" + end + + test "should create user" do + visit users_url + click_on "New user" + + fill_in "Email", with: "userthree@example.local" + fill_in "Password", with: "secret" + fill_in "Password confirmation", with: "secret" + click_on "Create User" + + assert_text "User was successfully created" + click_on "Back" + end + + test "should update User" do + visit user_url(@user) + click_on "Edit this user", match: :first + + fill_in "Email", with: "newemail@example.local" + fill_in "Password", with: "newpassword" + fill_in "Password confirmation", with: "newpassword" + click_on "Update User" + + assert_text "User was successfully updated" + click_on "Back" + end + + test "should destroy User" do + visit user_url(@user) + click_on "Destroy this user", match: :first + + assert_text "User was successfully destroyed" + end +end