Compare commits

..

3 commits

Author SHA1 Message Date
Christophe Robillard
7834dd7188 valid mood unique per day per user 2026-03-20 18:58:10 +01:00
Christophe Robillard
f396604316 fix modes factory 2026-03-20 18:58:10 +01:00
Christophe Robillard
eb81be50f9 add day logs controller 2026-03-20 18:58:10 +01:00
7 changed files with 129 additions and 12 deletions

View file

@ -7,6 +7,7 @@ class DayLogsController < ApplicationController
@day_log = Current.user.day_logs.build(day_log_params) @day_log = Current.user.day_logs.build(day_log_params)
if @day_log.save if @day_log.save
handle_mood(@day_log.day, params[:day_log][:mode_id])
redirect_to root_path redirect_to root_path
else else
render :new, status: :unprocessable_entity render :new, status: :unprocessable_entity
@ -15,6 +16,18 @@ class DayLogsController < ApplicationController
private 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 def day_log_params
params.expect(day_log: [ :day, :info ]) params.expect(day_log: [ :day, :info ])
end end

View file

@ -1,4 +1,19 @@
class Mood < ApplicationRecord class Mood < ApplicationRecord
belongs_to :user belongs_to :user
belongs_to :mode belongs_to :mode
validates :recorded_at, presence: true
validate :unique_per_day_and_user
private
def unique_per_day_and_user
return unless recorded_at && user
existing = user.moods.where.not(id: id).any? do |mood|
mood.recorded_at.to_date == recorded_at.to_date
end
errors.add(:recorded_at, :taken) if existing
end
end end

View file

@ -12,4 +12,10 @@
= f.label :info = f.label :info
= f.text_area :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 = f.submit

View file

@ -1,7 +1,6 @@
FactoryBot.define do FactoryBot.define do
factory :mode do factory :mode do
label { "MyString" } label { "MyString" }
slug { "MyString" }
color { "MyString" } color { "MyString" }
user { nil } user { nil }
end end

View file

@ -1,7 +1,7 @@
FactoryBot.define do FactoryBot.define do
factory :mood do factory :mood do
mode { "croisiere" } recorded_at { DateTime.parse("2026-01-15 10:00:00") }
recorded_at { DateTime.now }
association :user association :user
association :mode
end end
end end

View file

@ -1,7 +1,46 @@
require 'rails_helper' require 'rails_helper'
describe Mood, type: :model do describe Mood do
it 'works' do let(:user) { create(:user) }
expect(true) let(:mode) { create(:mode, user: user) }
subject { build(:mood, user: user, mode: mode, recorded_at: DateTime.parse("2026-01-15 10:00:00")) }
it { is_expected.to be_valid }
describe "validations" do
it "is invalid without a user" do
subject.user = nil
expect(subject).not_to be_valid
end
it "is invalid without a mode" do
subject.mode = nil
expect(subject).not_to be_valid
end
it "is invalid without a recorded_at" do
subject.recorded_at = nil
expect(subject).not_to be_valid
end
end
describe "uniqueness per day and user" do
it "is invalid if a mood already exists for the same day and user" do
create(:mood, user: user, mode: mode, recorded_at: DateTime.parse("2026-01-15 18:00:00"))
expect(subject).not_to be_valid
end
it "is valid if the same day exists but for a different user" do
other_user = create(:user)
other_mode = create(:mode, user: other_user)
create(:mood, user: other_user, mode: other_mode, recorded_at: DateTime.parse("2026-01-15 10:00:00"))
expect(subject).to be_valid
end
it "is valid if the same user has a mood on a different day" do
create(:mood, user: user, mode: mode, recorded_at: DateTime.parse("2026-01-14 10:00:00"))
expect(subject).to be_valid
end
end end
end end

View file

@ -1,8 +1,9 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe "DayLogs", type: :request do describe "DayLogs", type: :request do
let(:user) { create(:user) } let(:user) { create(:user) }
let(:day) { Date.new(2026, 1, 15) } let(:mode) { create(:mode, user: user) }
let(:day) { Date.parse("2026-01-15") }
describe "GET /day_logs/new" do describe "GET /day_logs/new" do
context "when not authenticated" do context "when not authenticated" do
@ -34,12 +35,56 @@ RSpec.describe "DayLogs", type: :request do
before { login_as(user) } before { login_as(user) }
context "with valid params" do context "with valid params" do
context "without mode" do
it "creates a day_log" do it "creates a day_log" do
expect { expect {
post day_logs_path, params: { day_log: { day: day, info: "Une info" } } post day_logs_path, params: { day_log: { day: day, info: "Une info" } }
}.to change(DayLog, :count).by(1) }.to change(DayLog, :count).by(1)
end 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 it "redirects after creation" do
post day_logs_path, params: { day_log: { day: day, info: "Une info" } } post day_logs_path, params: { day_log: { day: day, info: "Une info" } }
expect(response).to have_http_status(:redirect) expect(response).to have_http_status(:redirect)