Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

生理周期登録機能 #49

Merged
merged 11 commits into from
Nov 8, 2024
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ gem 'chartkick'

gem 'view_component'

gem 'kaminari'

group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
gem 'debug', platforms: %i[mri windows], require: 'debug/prelude'
Expand Down
13 changes: 13 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,18 @@ GEM
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
json (2.7.2)
kaminari (1.2.2)
activesupport (>= 4.1.0)
kaminari-actionview (= 1.2.2)
kaminari-activerecord (= 1.2.2)
kaminari-core (= 1.2.2)
kaminari-actionview (1.2.2)
actionview
kaminari-core (= 1.2.2)
kaminari-activerecord (1.2.2)
activerecord
kaminari-core (= 1.2.2)
kaminari-core (1.2.2)
language_server-protocol (3.17.0.3)
logger (1.6.1)
loofah (2.22.0)
Expand Down Expand Up @@ -400,6 +412,7 @@ DEPENDENCIES
image_processing (~> 1.2)
importmap-rails
jbuilder
kaminari
pg (~> 1.1)
puma (>= 5.0)
rails (~> 7.2.1)
Expand Down
10 changes: 5 additions & 5 deletions app/controllers/objectives_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class ObjectivesController < ApplicationController
before_action :set_objective, only: %i[show edit update destroy]

def index
@objectives = current_user.objectives.order(updated_at: :desc)
@objectives = current_user.objectives.order(updated_at: :desc).page(params[:page]).per(5)
end

def show; end
Expand All @@ -19,23 +19,23 @@ def edit; end
def create
@objective = Objective.new(objective_params)
if @objective.save
redirect_to @objective
redirect_to @objective, notice: t('objective.created')
else
render 'new'
render :new, status: :unprocessable_entity
end
end

def update
if @objective.update(objective_params)
redirect_to @objective
redirect_to @objective, notice: t('objective.updated')
else
render 'edit'
end
end

def destroy
@objective.destroy
redirect_to objectives_path
redirect_to objectives_path, notice: t('objective.destroyed')
Copy link
Owner Author

@sarii0213 sarii0213 Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

turbo_stream, htmlの二重のリクエストにレスポンスが返され、フラッシュメッセージが表示されない

Started DELETE "/objectives/17?_method=delete" for 192.168.65.1 at 2024-10-31 00:37:26 +0900
Processing by ObjectivesController#destroy as TURBO_STREAM
  Parameters: {"id"=>"17"}
  User Load (0.5ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  Objective Load (0.3ms)  SELECT "objectives".* FROM "objectives" WHERE "objectives"."user_id" = $1 AND "objectives"."id" = $2 LIMIT $3  [["user_id", 1], ["id", 17], ["LIMIT", 1]]
  ↳ app/controllers/objectives_controller.rb:44:in `set_objective'
  TRANSACTION (0.2ms)  BEGIN
  ↳ app/controllers/objectives_controller.rb:37:in `destroy'
  ActiveStorage::Attachment Load (0.2ms)  SELECT "active_storage_attachments".* FROM "active_storage_attachments" WHERE "active_storage_attachments"."record_id" = $1 AND "active_storage_attachments"."record_type" = $2 AND "active_storage_attachments"."name" = $3  [["record_id", 17], ["record_type", "Objective"], ["name", "images"]]
  ↳ app/controllers/objectives_controller.rb:37:in `destroy'
  Objective Destroy (0.8ms)  DELETE FROM "objectives" WHERE "objectives"."id" = $1  [["id", 17]]
  ↳ app/controllers/objectives_controller.rb:37:in `destroy'
  TRANSACTION (2.7ms)  COMMIT
  ↳ app/controllers/objectives_controller.rb:37:in `destroy'
Redirected to http://localhost:3006/objectives
Completed 302 Found in 28ms (ActiveRecord: 4.8ms (4 queries, 0 cached) | GC: 6.1ms)


Started GET "/objectives" for 192.168.65.1 at 2024-10-31 00:37:26 +0900
Processing by ObjectivesController#index as TURBO_STREAM
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  Rendering layout layouts/application.html.erb
  Rendering objectives/index.html.erb within layouts/application
  Objective Load (0.2ms)  SELECT "objectives".* FROM "objectives" WHERE "objectives"."user_id" = $1 ORDER BY "objectives"."updated_at" DESC LIMIT $2 OFFSET $3  [["user_id", 1], ["LIMIT", 5], ["OFFSET", 0]]
  ↳ app/views/objectives/index.html.erb:11
  Objective Count (0.2ms)  SELECT COUNT(*) FROM "objectives" WHERE "objectives"."user_id" = $1  [["user_id", 1]]
  ↳ app/views/objectives/index.html.erb:45
  Rendered objectives/index.html.erb within layouts/application (Duration: 6.4ms | GC: 2.0ms)
  Rendered layouts/_footer_menu.html.erb (Duration: 0.1ms | GC: 0.0ms)
  Rendered layout layouts/application.html.erb (Duration: 17.8ms | GC: 5.9ms)
Completed 200 OK in 25ms (Views: 18.0ms | ActiveRecord: 0.6ms (3 queries, 0 cached) | GC: 8.4ms)


Started GET "/objectives" for 192.168.65.1 at 2024-10-31 00:37:26 +0900
Processing by ObjectivesController#index as HTML
  User Load (0.2ms)  SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  Rendering layout layouts/application.html.erb
  Rendering objectives/index.html.erb within layouts/application
  Objective Load (0.2ms)  SELECT "objectives".* FROM "objectives" WHERE "objectives"."user_id" = $1 ORDER BY "objectives"."updated_at" DESC LIMIT $2 OFFSET $3  [["user_id", 1], ["LIMIT", 5], ["OFFSET", 0]]
  ↳ app/views/objectives/index.html.erb:11
  Objective Count (0.3ms)  SELECT COUNT(*) FROM "objectives" WHERE "objectives"."user_id" = $1  [["user_id", 1]]
  ↳ app/views/objectives/index.html.erb:45
  Rendered objectives/index.html.erb within layouts/application (Duration: 5.8ms | GC: 1.1ms)
  Rendered layouts/_footer_menu.html.erb (Duration: 1.1ms | GC: 1.0ms)
  Rendered layout layouts/application.html.erb (Duration: 14.6ms | GC: 2.9ms)
Completed 200 OK in 20ms (Views: 14.4ms | ActiveRecord: 0.8ms (3 queries, 0 cached) | GC: 3.9ms)

Copy link
Owner Author

@sarii0213 sarii0213 Nov 5, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

end

private
Expand Down
50 changes: 50 additions & 0 deletions app/controllers/periods_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# frozen_string_literal: true

class PeriodsController < ApplicationController
before_action :authenticate_user!
before_action :set_period, only: %i[edit update destroy]

def index
@periods = current_user.periods.order(started_on: :desc).page(params[:page]).per(5)
end

def new
@period = Period.new(started_on: Time.zone.today, ended_on: Time.zone.today.advance(weeks: 1))
end

def edit; end

def create
@period = Period.new(period_params)
if @period.save
flash[:notice] = t('period.created')
render turbo_stream: turbo_stream.action(:redirect, periods_path)
else
render :new, status: :unprocessable_entity
end
end

def update
if @period.update(period_params)
flash[:notice] = t('period.updated')
render turbo_stream: turbo_stream.action(:redirect, periods_path)
else
render :edit, status: :unprocessable_entity
end
end

def destroy
@period.destroy
flash.now[:notice] = t('period.destroyed')
end

private

def period_params
params.require(:period).permit(:started_on, :ended_on).merge(user_id: current_user.id)
end

def set_period
@period = current_user.periods.find(params[:id])
end
end
9 changes: 7 additions & 2 deletions app/controllers/records_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def update
@record = current_user.records.find_or_initialize_by(recorded_on: record_params[:recorded_on])
@record.assign_attributes(record_params)
if @record.save
message = Record::MessageGenerator.new(@record.recorded_on).generate
redirect_to records_path, notice: "記録完了! #{message}"
flash[:notice] = success_message
render turbo_stream: turbo_stream.action(:redirect, records_path)
else
render :new, status: :unprocessable_entity
end
Expand All @@ -27,4 +27,9 @@ def update
def record_params
params.require(:record).permit(:recorded_on, :weight, :body_fat)
end

def success_message
message = Record::MessageGenerator.new(@record.recorded_on).generate
"記録完了! #{message}"
end
end
1 change: 1 addition & 0 deletions app/controllers/user_settings_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

class UserSettingsController < ApplicationController
before_action :authenticate_user!
before_action :set_user

def show; end
Expand Down
15 changes: 5 additions & 10 deletions app/javascript/controllers/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,8 @@ window.Stimulus = application

export { application }

// Turbo frame requestからのリダイレクト(画面遷移)を可能に
document.addEventListener('turbo:before-fetch-response', (event) => {
if (typeof(event.detail.fetchResponse) !== 'undefined') {
const response = event.detail.fetchResponse.response
if (response.redirected) {
event.preventDefault()
Turbo.visit(response.url, { action: 'replace' })
}
}
})
// "Break out" of a frame from the server
// ref: https://github.com/hotwired/turbo-rails/pull/367#issuecomment-1934729149
Turbo.StreamActions.redirect = function() {
Turbo.visit(this.target);
};
36 changes: 36 additions & 0 deletions app/models/period.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

# == Schema Information
#
# Table name: periods
#
# id :bigint not null, primary key
# ended_on :date not null
# started_on :date not null
# created_at :datetime not null
# updated_at :datetime not null
# user_id :bigint not null
#
# Indexes
#
# index_periods_on_user_id_and_started_on (user_id,started_on) UNIQUE
#
# Foreign Keys
#
# fk_rails_... (user_id => users.id)
#
class Period < ApplicationRecord
belongs_to :user

validates :started_on, presence: true, uniqueness: { scope: :user_id }
validates :ended_on, presence: true, comparison: { greater_than: :started_on }
validate :date_difference

private

def date_difference
return unless ended_on > started_on.advance(weeks: 2)

errors.add(:ended_on, 'は開始日から2週間以内に設定してください')
end
end
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ class User < ApplicationRecord

has_many :objectives, dependent: :destroy
has_many :records, dependent: :destroy
has_many :periods, dependent: :destroy
end
3 changes: 3 additions & 0 deletions app/views/kaminari/_first_page.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<%= link_to url, class: 'item', title: t('views.pagination.first').html_safe, remote: remote do %>
<i class="angle double left icon"></i>
<% end %>
3 changes: 3 additions & 0 deletions app/views/kaminari/_gap.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="item">
<%= t('views.pagination.truncate').html_safe %>
</div>
3 changes: 3 additions & 0 deletions app/views/kaminari/_last_page.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<%= link_to url, class: 'item', title: t('views.pagination.last').html_safe, remote: remote do %>
<i class="angle double right icon"></i>
<% end %>
3 changes: 3 additions & 0 deletions app/views/kaminari/_next_page.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<%= link_to url, class: 'item', title: t('views.pagination.next').html_safe, remote: remote do %>
<i class="right angle icon"></i>
<% end %>
9 changes: 9 additions & 0 deletions app/views/kaminari/_page.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<% if page.current? %>
<%= link_to url, class: 'item active', title: page, remote: remote do %>
<%= page %>
<% end %>
<% else %>
<%= link_to url, class: 'item', title: page, remote: remote do %>
<%= page %>
<% end %>
<% end %>
15 changes: 15 additions & 0 deletions app/views/kaminari/_paginator.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<%= paginator.render do %>
<nav class="ui pagination menu">
<%= first_page_tag unless current_page.first? %>
<%= prev_page_tag unless current_page.first? %>
<% each_page do |page| %>
<% if page.left_outer? || page.right_outer? || page.inside_window? %>
<%= page_tag page %>
<% elsif !page.was_truncated? %>
<%= gap_tag %>
<% end %>
<% end %>
<%= next_page_tag unless current_page.last? %>
<%= last_page_tag unless current_page.last? %>
</nav>
<% end %>
3 changes: 3 additions & 0 deletions app/views/kaminari/_prev_page.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<%= link_to url, class: 'item', title: t('views.pagination.previous').html_safe, remote: remote do %>
<i class="left angle icon"></i>
<% end %>
4 changes: 2 additions & 2 deletions app/views/layouts/_footer_menu.html.erb
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<div class="ui borderless bottom fixed labeled icon menu three item grey">
<%= link_to objectives_path, class: "item #{'active' if current_page?(objectives_path)}" do %>
<%= link_to objectives_path, class: "item #{'active' if current_page?(objectives_path) || current_page?(root_path)}" do %>
<i class="compass icon"></i>vision board
<% end %>
<%= link_to records_path, class: "item #{'active' if current_page?(records_path)}" do %>
<i class="map icon"></i>weight
<% end %>
<%= link_to user_setting_path, class: "item #{'active' if current_page?(root_path)}" do %>
<%= link_to user_setting_path, class: "item #{'active' if current_page?(user_setting_path)}" do %>
<i class="cogs icon"></i>setting
<% end %>
</div>
9 changes: 3 additions & 6 deletions app/views/objectives/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
<div data-controller="form">
<%= form_with(model: objective, class: 'ui form') do |form| %>
<%= form_with(model: objective, class: "ui form #{objective.errors.any? ? 'error' : ''}", data: { turbo: false }) do |form| %>
<% if objective.errors.any? %>
<div style="color: red">
<h2><%= pluralize(objective.errors.count, "error") %> prohibited this objective from being saved:</h2>

<ul>
<div class="ui error message">
<ul class="list">
<% objective.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>

<div class="inline fields">
<label for="objective_objective_type">タイプ:</label>
<div class="field">
Expand Down
4 changes: 4 additions & 0 deletions app/views/objectives/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@
</div>
<% end %>
</div>

<div style="margin-top:50px; text-align:center">
<%= paginate @objectives %>
</div>
22 changes: 22 additions & 0 deletions app/views/periods/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<%= turbo_frame_tag 'form' do %>
<%= form_with model: period, method: :post, class: "ui form #{period.errors.any? ? 'error' : ''}", data: { modal_target: 'form', action: 'turbo:submit-end->modal#close' } do |f| %>
<div class="field">
<%= f.label :started_on, '開始日' %>
<%= f.date_field :started_on %>
</div>
<div class="field">
<%= f.label :ended_on, '終了日' %>
<%= f.date_field :ended_on %>
</div>
<% if period.errors.any? %>
<div class="ui error message">
<ul class="list">
<% period.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<%= f.submit '登録', class: 'actions ui fluid large teal submit button' %>
<% end %>
<% end %>
13 changes: 13 additions & 0 deletions app/views/periods/_period.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<div style="display: flex; justify-content: space-between; padding-right: 10px">
<span><%= period.started_on %> - <%= period.ended_on %></span>
<div>
<%# TODO: edit, deleteをiconに %>
<%= link_to edit_period_path(period), data: { turbo_frame: period } do %>
<i class="edit icon"></i>
<% end %>
<%= link_to period, data: { turbo_method: :delete, turbo_confirm: '削除しますか?' } do %>
<i class="trash icon"></i>
<% end %>
</div>
</div>
<div class="ui divider"></div>
2 changes: 2 additions & 0 deletions app/views/periods/destroy.turbo_stream.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<%= turbo_stream.remove @period %>
<%= turbo_stream_flash %>
29 changes: 29 additions & 0 deletions app/views/periods/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<%= turbo_frame_tag @period do %>
<%= form_with model: @period, method: :put, class: "ui form #{@period.errors.any? ? 'error' : ''}" do |f| %>
<div style="display: flex; justify-content: space-between">
<div style="display: flex; align-items: center;">
<div class="inline field" style="margin:0">
<%= f.date_field :started_on %>
</div>
<div style="padding:10px">-</div>
<div class="inline field" style="margin:0">
<%= f.date_field :ended_on %>
</div>
</div>
<div style="display: flex; align-items: center">
<%= f.submit '更新', class: 'ui mini button' %>
<%= link_to 'キャンセル', periods_path, class: 'ui mini button' %>
</div>
</div>
<% if @period.errors.any? %>
<div class="ui error message">
<ul class="list">
<% @period.errors.each do |error| %>
<li><%= error.full_message %></li>
<% end %>
</ul>
</div>
<% end %>
<% end %>
<div class="ui divider"></div>
<% end %>
Loading