From 93b578c3cfba5db577484ff322aeb79ca69e0e2d Mon Sep 17 00:00:00 2001 From: Christophe Robillard Date: Thu, 19 Mar 2026 21:21:28 +0100 Subject: [PATCH] create day_log --- app/controllers/day_logs_controller.rb | 34 ++++++++ app/models/user.rb | 1 + app/views/day_logs/new.html.haml | 21 +++++ config/routes.rb | 2 + spec/factories/user.rb | 3 +- spec/requests/day_logs_spec.rb | 108 +++++++++++++++++++++++++ spec/support/authentication_helper.rb | 12 +++ 7 files changed, 180 insertions(+), 1 deletion(-) create mode 100644 app/controllers/day_logs_controller.rb create mode 100644 app/views/day_logs/new.html.haml create mode 100644 spec/requests/day_logs_spec.rb create mode 100644 spec/support/authentication_helper.rb diff --git a/app/controllers/day_logs_controller.rb b/app/controllers/day_logs_controller.rb new file mode 100644 index 0000000..45aeba2 --- /dev/null +++ b/app/controllers/day_logs_controller.rb @@ -0,0 +1,34 @@ +class DayLogsController < ApplicationController + def new + @day_log = DayLog.new + end + + def create + @day_log = Current.user.day_logs.build(day_log_params) + + if @day_log.save + handle_mood(@day_log.day, params[:day_log][:mode_id]) + redirect_to root_path + else + render :new, status: :unprocessable_entity + end + end + + private + + def handle_mood(day, mode_id) + return if mode_id.blank? + + mood = Current.user.moods.find_by(recorded_at: day.beginning_of_day..day.end_of_day) + + if mood + mood.update(mode_id: mode_id) + else + Current.user.moods.create(mode_id: mode_id, recorded_at: day.to_datetime) + end + end + + def day_log_params + params.expect(day_log: [ :day, :info ]) + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 156f55a..7df92ba 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,6 +3,7 @@ class User < ApplicationRecord has_many :sessions, dependent: :destroy has_many :moods, -> { order "recorded_at" } has_many :modes + has_many :day_logs normalizes :email_address, with: ->(e) { e.strip.downcase } diff --git a/app/views/day_logs/new.html.haml b/app/views/day_logs/new.html.haml new file mode 100644 index 0000000..0bf5050 --- /dev/null +++ b/app/views/day_logs/new.html.haml @@ -0,0 +1,21 @@ +%h1 Nouveau journal + += form_with model: @day_log do |f| + - @day_log.errors.full_messages.each do |msg| + %p= msg + + .field + = f.label :day + = f.date_field :day + + .field + = f.label :info + = f.text_area :info + + .field + = label_tag :mode_id, "Mode" + = select_tag "day_log[mode_id]", + options_from_collection_for_select(Current.user.modes, :id, :label), + include_blank: true + + = f.submit diff --git a/config/routes.rb b/config/routes.rb index 85fba14..97b69df 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -21,4 +21,6 @@ Rails.application.routes.draw do patch "/invite/:token", to: "invitations#update", as: :invitation get "/moods", to: "moods#index", as: :dashboard + + resources :day_logs, only: [ :new, :create ] end diff --git a/spec/factories/user.rb b/spec/factories/user.rb index 984ad18..449421e 100644 --- a/spec/factories/user.rb +++ b/spec/factories/user.rb @@ -2,6 +2,7 @@ FactoryBot.define do factory :user do sequence(:email_address) { |n| "user#{n}@example.com" } sequence(:username) { |n| "user#{n}" } - password_digest { BCrypt::Password.create('password123') } + password { "obanonalors" } + password_digest { BCrypt::Password.create(password) } end end diff --git a/spec/requests/day_logs_spec.rb b/spec/requests/day_logs_spec.rb new file mode 100644 index 0000000..40b6e77 --- /dev/null +++ b/spec/requests/day_logs_spec.rb @@ -0,0 +1,108 @@ +require 'rails_helper' + +describe "DayLogs", type: :request do + let(:user) { create(:user) } + let(:mode) { create(:mode, user: user) } + let(:day) { Date.parse("2026-01-15") } + + describe "GET /day_logs/new" do + context "when not authenticated" do + it "redirects to the login page" do + get new_day_log_path + expect(response).to redirect_to(new_session_path) + end + end + + context "when authenticated" do + before { login_as(user) } + + it "returns http success" do + get new_day_log_path + expect(response).to have_http_status(:success) + end + end + end + + describe "POST /day_logs" do + context "when not authenticated" do + it "redirects to the login page" do + post day_logs_path, params: { day_log: { day: day, info: "Une info" } } + expect(response).to redirect_to(new_session_path) + end + end + + context "when authenticated" do + before { login_as(user) } + + context "with valid params" do + context "without mode" do + it "creates a day_log" do + expect { + post day_logs_path, params: { day_log: { day: day, info: "Une info" } } + }.to change(DayLog, :count).by(1) + end + + it "does not create a mood" do + expect { + post day_logs_path, params: { day_log: { day: day, info: "Une info" } } + }.not_to change(Mood, :count) + end + end + + context "with mode, no existing mood" do + it "creates a day_log" do + expect { + post day_logs_path, params: { day_log: { day: day, info: "Une info", mode_id: mode.id } } + }.to change(DayLog, :count).by(1) + end + + it "creates a mood" do + expect { + post day_logs_path, params: { day_log: { day: day, info: "Une info", mode_id: mode.id } } + }.to change(Mood, :count).by(1) + end + end + + context "with mode, existing mood" do + let!(:existing_mood) { create(:mood, user: user, mode: mode, recorded_at: DateTime.parse("2026-01-15 08:00:00")) } + let(:other_mode) { create(:mode, user: user) } + + it "creates a day_log" do + expect { + post day_logs_path, params: { day_log: { day: day, info: "Une info", mode_id: other_mode.id } } + }.to change(DayLog, :count).by(1) + end + + it "does not create a new mood" do + expect { + post day_logs_path, params: { day_log: { day: day, info: "Une info", mode_id: other_mode.id } } + }.not_to change(Mood, :count) + end + + it "updates the existing mood mode" do + post day_logs_path, params: { day_log: { day: day, info: "Une info", mode_id: other_mode.id } } + expect(existing_mood.reload.mode).to eq(other_mode) + end + end + + it "redirects after creation" do + post day_logs_path, params: { day_log: { day: day, info: "Une info" } } + expect(response).to have_http_status(:redirect) + end + end + + context "with invalid params" do + it "does not create a day_log" do + expect { + post day_logs_path, params: { day_log: { day: nil, info: nil } } + }.not_to change(DayLog, :count) + end + + it "returns unprocessable entity" do + post day_logs_path, params: { day_log: { day: nil, info: nil } } + expect(response).to have_http_status(:unprocessable_entity) + end + end + end + end +end diff --git a/spec/support/authentication_helper.rb b/spec/support/authentication_helper.rb new file mode 100644 index 0000000..2287728 --- /dev/null +++ b/spec/support/authentication_helper.rb @@ -0,0 +1,12 @@ +module AuthenticationHelper + def login_as(user) + post session_path, params: { + email_address: user.email_address, + password: user.password + } + end +end + +RSpec.configure do |config| + config.include AuthenticationHelper, type: :request +end