Open kodamarisa opened 1 week ago
app/javascript/packs/schedule.js
document.addEventListener("DOMContentLoaded", () => {
const scheduleModalEl = document.getElementById("scheduleModal");
const editModalEl = document.getElementById("editModal");
const scheduleForm = document.getElementById("schedule-form");
// モーダルのインスタンスを作成
const scheduleModal = scheduleModalEl ? new bootstrap.Modal(scheduleModalEl) : null;
const editModal = editModalEl ? new bootstrap.Modal(editModalEl) : null;
// モーダルを開いてスケジュールを表示する関数
function openScheduleModal(date, calendarId) {
fetch(`/calendars/${calendarId}/schedules?date=${date}`, {
headers: { "X-Requested-With": "XMLHttpRequest" },
})
.then((response) => {
if (!response.ok) throw new Error("スケジュールの取得に失敗しました。");
return response.text();
})
.then((html) => {
document.getElementById("schedule-details").innerHTML = html;
scheduleModal.show(); // スケジュールモーダルを表示
registerEditButtonListeners(); // 編集ボタンのリスナーを登録
})
.catch((error) => {
console.error(error);
alert("スケジュールの読み込みに失敗しました。");
});
}
// 編集ボタンのリスナーを登録する関数
function registerEditButtonListeners() {
document.querySelectorAll(".edit-schedule-btn").forEach((button) => {
button.addEventListener("click", () => {
const scheduleId = button.dataset.scheduleId;
const exerciseName = button.dataset.exerciseName;
const reps = button.dataset.reps;
const sets = button.dataset.sets;
const date = button.dataset.date;
// モーダルのタイトルにエクササイズ名を表示
document.getElementById("exercise_name_display").textContent = exerciseName;
// フォームに値を設定
document.getElementById("exercise_id").value = scheduleId;
document.getElementById("schedule_date").value = date;
document.getElementById("reps").value = reps;
document.getElementById("sets").value = sets;
scheduleModal.hide(); // スケジュールモーダルを隠す
editModal.show(); // 編集モーダルを表示
});
});
}
// カレンダーの日付クリック処理
document.querySelectorAll(".calendar-date").forEach((element) => {
element.addEventListener("click", (event) => {
event.preventDefault();
const date = element.dataset.date;
const calendarId = element.dataset.calendarId;
openScheduleModal(date, calendarId); // モーダルを開く
});
});
// フォームの送信処理
if (scheduleForm) {
scheduleForm.addEventListener("submit", (event) => {
event.preventDefault();
const formData = new FormData(scheduleForm);
fetch(scheduleForm.action, {
method: scheduleForm.method,
body: formData,
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then((response) => {
if (!response.ok) throw new Error("保存に失敗しました。");
return response.json();
})
.then(() => {
editModal.hide(); // 編集モーダルを隠す
alert("スケジュールが保存されました。");
// カレンダー更新処理をここに追加
})
.catch((error) => console.error(error));
});
}
});
こうしたところ、編集ボタンでの切り替えができるようになりましたが、追加ボタンでの筋トレ一覧へのリダレクトができなくなってしまいました。 もう少し、前のコードと見比べながら、修正できそうか試してみます。
app/javascript/packs/schedule.js
document.addEventListener("DOMContentLoaded", () => {
const scheduleModalEl = document.getElementById("scheduleModal");
const editModalEl = document.getElementById("editModal");
const scheduleForm = document.getElementById("schedule-form");
// モーダルのインスタンスを作成
const scheduleModal = scheduleModalEl ? new bootstrap.Modal(scheduleModalEl) : null;
const editModal = editModalEl ? new bootstrap.Modal(editModalEl) : null;
// モーダルを開いてスケジュールを表示する関数
function openScheduleModal(date, calendarId) {
fetch(`/calendars/${calendarId}/schedules?date=${date}`, {
headers: { "X-Requested-With": "XMLHttpRequest" },
})
.then((response) => {
if (!response.ok) throw new Error("スケジュールの取得に失敗しました。");
return response.text();
})
.then((html) => {
document.getElementById("schedule-details").innerHTML = html;
scheduleModal.show(); // スケジュールモーダルを表示
registerEditButtonListeners(); // 編集ボタンのリスナーを登録
registerAddButtonListener(); // 追加ボタンのリスナーを登録
})
.catch((error) => {
console.error(error);
alert("スケジュールの読み込みに失敗しました。");
});
}
// 編集ボタンのリスナーを登録する関数
function registerEditButtonListeners() {
document.querySelectorAll(".edit-schedule-btn").forEach((button) => {
button.addEventListener("click", () => {
const scheduleId = button.dataset.scheduleId;
const exerciseName = button.dataset.exerciseName;
const reps = button.dataset.reps;
const sets = button.dataset.sets;
const date = button.dataset.date;
// モーダルのタイトルにエクササイズ名を表示
document.getElementById("exercise_name_display").textContent = exerciseName;
// フォームに値を設定
document.getElementById("exercise_id").value = scheduleId;
document.getElementById("schedule_date").value = date;
document.getElementById("reps").value = reps;
document.getElementById("sets").value = sets;
scheduleModal.hide(); // スケジュールモーダルを隠す
editModal.show(); // 編集モーダルを表示
});
});
}
// 追加ボタンのリスナーを登録する関数
function registerAddButtonListener() {
const addScheduleBtn = document.getElementById("add-schedule-btn");
if (addScheduleBtn) {
addScheduleBtn.addEventListener("click", () => {
scheduleModal.hide(); // モーダルを閉じる
window.location.href = "/exercises"; // 筋トレ一覧にリダイレクト
});
}
}
// モーダル閉じるときの後処理
function cleanupModal() {
document.getElementById("exercise_name_display").textContent = "";
const exerciseIdField = document.querySelector("#schedule-form input[name='schedule[exercise_id]']");
if (exerciseIdField) exerciseIdField.value = "";
// モーダルの背景削除
document.body.classList.remove("modal-open");
const backdrop = document.querySelector(".modal-backdrop");
if (backdrop) backdrop.remove();
}
// カレンダーの日付クリック処理
document.querySelectorAll(".calendar-date").forEach((element) => {
element.addEventListener("click", (event) => {
event.preventDefault();
const date = element.dataset.date;
const calendarId = element.dataset.calendarId;
openScheduleModal(date, calendarId); // モーダルを開く
});
});
// フォームの送信処理
if (scheduleForm) {
scheduleForm.addEventListener("submit", (event) => {
event.preventDefault();
const formData = new FormData(scheduleForm);
fetch(scheduleForm.action, {
method: scheduleForm.method,
body: formData,
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then((response) => {
if (!response.ok) throw new Error("保存に失敗しました。");
return response.json();
})
.then(() => {
editModal.hide(); // 編集モーダルを隠す
alert("スケジュールが保存されました。");
// カレンダー更新処理をここに追加
})
.catch((error) => console.error(error));
});
}
// モーダルが閉じられたときにクリーンアップ処理を呼び出す
scheduleModalEl.addEventListener('hidden.bs.modal', cleanupModal);
});
こうしたら、問題なく、筋トレ一覧へのリダレクトも行えるようになりました。 しかし、動作を確認したところ、編集した内容がうまく保存できず、 https://gyazo.com/3d35ade34e95d9a21b9af8734c385ca9 このようなエラーが出現しています。 現在、原因の絞り込みをしています。
現在、 編集で日付を変更し、保存しようとしたら"exercise_id"が空白であるため、エラーが発生し、保存ができない。 "exercise_id"に編集ボタンを押された筋トレのidを入れれるようにし、日付や回数を変更してもカレンダーに反映されるようにしたい。
Started PUT "/calendars/56/schedules/20" for ::1 at 2024-10-28 12:42:52 +0900
Processing by SchedulesController#update as */*
Parameters: {"authenticity_token"=>"[FILTERED]", "schedule"=>{"exercise_id"=>"", "date"=>"2024-10-28", "repetitions"=>"4", "sets"=>"2"}, "calendar_id"=>"56", "id"=>"20"}
Calendar Load (1.0ms) SELECT "calendars".* FROM "calendars" WHERE "calendars"."id" = $1 LIMIT $2 [["id", 56], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:39:in `set_current_calendar'
CACHE Calendar Load (0.0ms) SELECT "calendars".* FROM "calendars" WHERE "calendars"."id" = $1 LIMIT $2 [["id", 56], ["LIMIT", 1]]
↳ app/controllers/schedules_controller.rb:92:in `set_calendar'
Set Calendar: #<Calendar id: 56, title: "あ", image: nil, calendar_color: nil, calendar_type: nil, user_type: "User", user_id: 4, created_at: "2024-09-30 08:55:52.401595000 +0000", updated_at: "2024-09-30 09:32:30.371458000 +0000">
Schedule Load (1.5ms) SELECT "schedules".* FROM "schedules" WHERE "schedules"."calendar_id" = $1 AND "schedules"."id" = $2 LIMIT $3 [["calendar_id", 56], ["id", 20], ["LIMIT", 1]]
↳ app/controllers/schedules_controller.rb:97:in `set_schedule'
Set Schedule: #<Schedule id: 20, calendar_id: 56, exercise_id: 1, date: "2024-10-28", repetitions: 1, duration: nil, created_at: "2024-10-18 07:16:08.417868000 +0000", updated_at: "2024-10-18 07:16:08.417868000 +0000", distance: nil, sets: 1>
UPDATE: Schedule ID: 20, Params: #<ActionController::Parameters {"_method"=>"put", "authenticity_token"=>"yBVLEyh0jwspLdg7Fq7DdD09fym_zcoivPNQ5tcxERHkRA2kbJSw9N6RjxRS_5lDs3rHDgIrymI_n3idkh1YcQ", "schedule"=>{"exercise_id"=>"", "date"=>"2024-10-28", "repetitions"=>"4", "sets"=>"2"}, "controller"=>"schedules", "action"=>"update", "calendar_id"=>"56", "id"=>"20"} permitted: false>
Exercise ID is missing.
Rendering layout layouts/application.html.erb
Rendering schedules/edit.html.erb within layouts/application
Rendered schedules/edit.html.erb within layouts/application (Duration: 14.7ms | Allocations: 5480)
Rendered layout layouts/application.html.erb (Duration: 15.0ms | Allocations: 5556)
Completed 500 Internal Server Error in 31ms (ActiveRecord: 2.5ms | Allocations: 8466)
ActionView::Template::Error (undefined method `schedule_path' for #<ActionView::Base:0x0000000000e240>
recipient.public_send(method, *args, options)
^^^^^^^^^^^^):
1: <%= form_with(model: @schedule, local: true) do |form| %>
2: <div class="field">
3: <%= form.label :date %>
4: <%= form.date_field :date, value: @schedule.date %>
app/views/schedules/edit.html.erb:1
app/controllers/schedules_controller.rb:56:in `block (2 levels) in update'
app/controllers/schedules_controller.rb:55:in `update'
"exercise_id"が空白であるため、編集ボタンを押された筋トレのidを入れれるようにしたい。
該当のソースコード app/javascript/packs/schedule.js
document.addEventListener("DOMContentLoaded", () => {
const scheduleModalEl = document.getElementById("scheduleModal");
const editModalEl = document.getElementById("editModal");
const scheduleForm = document.getElementById("schedule-form");
const scheduleModal = scheduleModalEl ? new bootstrap.Modal(scheduleModalEl) : null;
const editModal = editModalEl ? new bootstrap.Modal(editModalEl) : null;
function openScheduleModal(date, calendarId) {
console.log("Calendar ID:", calendarId, "Date:", date); // デバッグログ
fetch(`/calendars/${calendarId}/schedules?date=${date}`, {
headers: { "X-Requested-With": "XMLHttpRequest" },
})
.then((response) => {
if (!response.ok) throw new Error("スケジュールの取得に失敗しました。");
return response.text();
})
.then((html) => {
document.getElementById("schedule-details").innerHTML = html;
scheduleModal?.show();
registerEditButtonListeners();
registerAddButtonListener();
})
.catch((error) => {
console.error(error);
alert("スケジュールの読み込みに失敗しました。");
});
}
// 編集ボタンのリスナーを登録する関数
function registerEditButtonListeners() {
document.querySelectorAll(".edit-schedule-btn").forEach((button) => {
button.addEventListener("click", () => {
const scheduleId = button.dataset.scheduleId;
const calendarId = button.dataset.calendarId;
const exerciseId = button.dataset.exerciseId;
const exerciseName = button.dataset.exerciseName;
const reps = button.dataset.reps;
const sets = button.dataset.sets;
const date = button.dataset.date;
console.log({
scheduleId,
calendarId,
exerciseId,
exerciseName,
reps,
sets,
date
});
// Calendar IDのチェック
if (!calendarId) {
console.error("Calendar ID is missing");
alert("カレンダーIDが見つかりません。");
return;
}
console.log("Editing Schedule - Calendar ID:", calendarId, "Schedule ID:", scheduleId); // デバッグログ
// モーダルのタイトルにエクササイズ名を表示
document.getElementById("exercise_name_display").textContent = exerciseName;
// フォームに値を設定
document.getElementById("schedule_exercise_id").value = exerciseId;
document.getElementById("schedule_date").value = date;
document.getElementById("reps").value = reps;
document.getElementById("sets").value = sets;
// フォームのactionを正しいURLに設定
const scheduleForm = document.getElementById("schedule-form");
scheduleForm.action = `/calendars/${calendarId}/schedules/${scheduleId}`;
scheduleModal.hide(); // スケジュールモーダルを隠す
editModal.show(); // 編集モーダルを表示
});
});
}
function registerAddButtonListener() {
const addScheduleBtn = document.getElementById("add-schedule-btn");
if (addScheduleBtn) {
addScheduleBtn.addEventListener("click", () => {
scheduleModal?.hide();
window.location.href = "/exercises";
});
}
}
function cleanupModal() {
document.getElementById("exercise_name_display").textContent = "";
const exerciseIdField = document.querySelector("#schedule-form input[name='schedule[exercise_id]']");
if (exerciseIdField) exerciseIdField.value = "";
document.body.classList.remove("modal-open");
const backdrop = document.querySelector(".modal-backdrop");
if (backdrop) backdrop.remove();
}
document.querySelectorAll(".calendar-date").forEach((element) => {
element.addEventListener("click", (event) => {
event.preventDefault();
const date = element.dataset.date;
const calendarId = element.dataset.calendarId;
// Calendar IDのチェック
if (!calendarId) {
console.error("Calendar ID is missing");
alert("カレンダーIDが取得できませんでした。");
return;
}
console.log("Opening Schedule Modal - Calendar ID:", calendarId, "Date:", date); // デバッグログ
openScheduleModal(date, calendarId);
});
});
if (scheduleForm) {
scheduleForm.addEventListener("submit", (event) => {
event.preventDefault();
const formData = new FormData(scheduleForm);
fetch(scheduleForm.action, {
method: scheduleForm.method,
body: formData,
headers: { 'X-Requested-With': 'XMLHttpRequest' }
})
.then((response) => {
if (!response.ok) throw new Error("保存に失敗しました。");
return response.json();
})
.then(() => {
editModal?.hide();
alert("スケジュールが保存されました。");
})
.catch((error) => console.error(error));
});
}
if (scheduleModalEl) {
scheduleModalEl.addEventListener('hidden.bs.modal', cleanupModal);
}
});
app/views/schedules/_schedule_details.html.erb
<div class="schedule-header">
<h5><%= date %></h5>
</div>
<% if schedules.any? %> <% schedules.each do |schedule| %>
<%= schedule.exercise.name %> <%= schedule.repetitions %> 回 × <%= schedule.sets %> セット
<% end %> <% else %>
この日にスケジュールはありません。
<% end %>
<% if schedules.count < 3 %>
<% else %>
これ以上スケジュールを追加できません。
<% end %>
app/views/schedules/_edit_modal.html.erb
app/controllers/schedules_controller.rb
class SchedulesController < ApplicationController before_action :set_calendar before_action :set_schedule, only: [:show, :edit, :update, :destroy]
def new logger.debug "NEW: Calendar ID: #{params[:calendar_id]}, Exercise ID: #{params[:exercise_id]}, Date: #{params[:date]}"
@calendar = Calendar.find(params[:calendar_id])
@exercise = Exercise.find(params[:exercise_id])
@schedule = @calendar.schedules.build(exercise: @exercise)
@exercises = Exercise.all
@selected_exercise = @exercise
@selected_date = params[:date] ? Date.parse(params[:date]) : Date.today
end
def create logger.debug "CREATE: Params: #{params.inspect}"
@schedule = @calendar.schedules.build(schedule_params)
if @schedule.save
logger.info "Schedule successfully created: #{@schedule.inspect}"
render json: { status: 'success', schedule: @schedule }, status: :created
else
logger.error "Failed to create schedule: #{@schedule.errors.full_messages}"
render json: { status: 'error', errors: @schedule.errors.full_messages }, status: :unprocessable_entity
end
end
def index logger.debug "INDEX: Calendar ID: #{params[:calendar_id]}, Date: #{params[:date]}"
@calendar = Calendar.find(params[:calendar_id])
@schedules = @calendar.schedules.where(date: params[:date])
@exercises = Exercise.all
if params[:exercise_id]
@exercise = Exercise.find(params[:exercise_id])
logger.debug "Selected Exercise: #{@exercise.name}"
end
respond_to do |format|
format.html { render partial: 'schedules/schedule_details', locals: { schedules: @schedules, date: params[:date] } }
format.js
end
end
def update logger.debug "UPDATE: Schedule ID: #{@schedule.id}, Params: #{params.inspect}"
# exercise_idが空でないことを確認
if params[:schedule][:exercise_id].blank?
logger.error "Exercise ID is missing."
@exercises = Exercise.all # エクササイズのリストを再取得
respond_to do |format|
format.html { render :edit, alert: 'エクササイズを選択してください。' }
format.js { render json: { status: 'error', errors: ['エクササイズを選択してください。'] }, status: :unprocessable_entity }
end
return # ここで処理を終了
end
# スケジュールを更新
if @schedule.update(schedule_params)
logger.info "Schedule updated: #{@schedule.inspect}"
respond_to do |format|
format.html { redirect_to calendar_path(@calendar), notice: 'スケジュールが正常に更新されました。' }
format.js
end
else
logger.error "Failed to update schedule: #{@schedule.errors.full_messages}"
@exercises = Exercise.all
respond_to do |format|
format.html { render :edit }
format.js { render json: { status: 'error', errors: @schedule.errors.full_messages }, status: :unprocessable_entity }
end
end
end
def destroy logger.info "DESTROY: Schedule ID: #{@schedule.id}"
@schedule.destroy
respond_to do |format|
format.html { redirect_to calendar_path(@calendar), notice: 'スケジュールが正常に削除されました。' }
format.js
end
end
private
def set_calendar @calendar = Calendar.find(params[:calendar_id]) logger.debug "Set Calendar: #{@calendar.inspect}" end
def set_schedule @schedule = @calendar.schedules.find(params[:id]) logger.debug "Set Schedule: #{@schedule.inspect}" end
def schedule_params params.require(:schedule).permit(:exercise_id, :repetitions, :sets, :date) end end
app/models/schedule.rb
class Schedule < ApplicationRecord belongs_to :calendar belongs_to :exercise validates :date, presence: true
def start_time self.date end end
app/models/exercise.rb
class Exercise < ApplicationRecord has_many :schedules, dependent: :destroy
def self.ransackable_attributes(auth_object = nil) ["created_at", "description", "difficulty", "duration", "id", "name", "updated_at", "target_muscles"] end
def self.ransackable_associations(auth_object = nil) [] # 今回はアソシエーションでの検索は許可しない end end
config/routes.rb
Rails.application.routes.draw do get 'static_pages/privacy_policy' get 'static_pages/terms_of_service' root 'calendars#new'
devise_for :users, controllers: { sessions: 'users/sessions', registrations: 'users/registrations', passwords: 'users/passwords', confirmations: 'users/confirmations', unlocks: 'users/unlocks', }
devise_scope :user do get '/login', to: 'users/sessions#new', as: :new_line_user_session post '/login', to: 'users/sessions#create' get '/logout', to: 'users/sessions#destroy', as: :destroy_line_user_session get '/line_login', to: 'sessions#line_login', as: :login_with_line end
get '/auth/:provider/callback', to: 'sessions#create' get '/auth/failure', to: redirect('/')
authenticated :user do get '/choose_registration', to: 'users/registrations#choose', as: :choose_registration get '/profile', to: 'users#profile', as: :user_profile end
resources :calendars, except: [:destroy, :update] do resources :schedules, only: [:index, :show, :new, :create, :edit, :update, :destroy] end
resources :exercises, only: [:index, :show] do collection do get :autocomplete end resources :bookmarks, only: [:create, :destroy], shallow: false end
resources :registrations, only: [:new] get '/line_registration', to: 'line_users#line_registration', as: :line_registration get '/email_registration', to: 'registrations#email_registration', as: :email_registration
resources :line_users, only: [:show, :new, :create]
resources :customizes, only: [:new, :edit, :create, :update]
resources :bookmarks, only: [:index]
scope controller: :static_pages do get :privacy_policy get :terms_of_service end
end
- 試したこと
デバックログで"exercise_id"が渡せていないことまではわかりましたが、どうやったら、編集ボタンでモーダルを開かれた筋トレのidが渡せるのかがわかりません。
何かアイディアや助言等あればお願いいたします。
hidden_fieldに何もvalueを設定していなのでnilになるとかですかね?
<%= form.hidden_field :exercise_id, id: 'schedule_exercise_id' %>
<div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="editModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="editModalLabel">
Edit Schedule: <span id="exercise_name_display"></span>
</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<%= form_with model: [@calendar, @schedule], local: true, method: :put, id: "schedule-form" do |form| %>
<%= form.hidden_field :exercise_id, id: 'schedule_exercise_id' %>
<div class="mb-3">
<label for="schedule_date" class="form-label">Schedule Date</label>
<%= form.date_field :date, class: "form-control", id: "schedule_date", required: true %>
</div>
<div class="mb-3">
<label for="reps" class="form-label">Reps/Distance</label>
<%= form.number_field :repetitions, class: "form-control", id: "reps", min: 1, required: true %>
</div>
<div class="mb-3">
<label for="sets" class="form-label">Sets</label>
<%= form.number_field :sets, class: "form-control", id: "sets", min: 1, required: true %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<%= form.submit "Save changes", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
</div>
</div>
valueの設定を確認するため、app/javascript/packs/schedule.jsに
console.log("Opening edit modal with data:", {
scheduleId,
calendarId,
exerciseId,
exerciseName,
reps,
sets,
date
});
このログを追加しました。この状態で、 https://gyazo.com/a868035e0db2d7b3a33a3b1f1eb5206d この一番上のスクワットの編集ボタンを押すと https://gyazo.com/97a6a922f3490a2e0e8c88d3441fdd21 このログが出たため、セット数を2から5に変更し、Saveボタンを押したところ、 https://gyazo.com/11935e1047e5b4969a14978326e42bfd こうなっています。 この、編集ボタンを押し、編集モーダルに切り替わる際一瞬だけ、Edit Schedule:の横にスクワットの文字が表示されましたが、すぐに消えてしまい、Edit Schedule:の横が空白になってしまっています。ターミナルの方のエラーは持続してみられます。
Started PUT "/calendars/56/schedules/19" for ::1 at 2024-10-28 16:06:07 +0900
Processing by SchedulesController#update as */*
Parameters: {"authenticity_token"=>"[FILTERED]", "schedule"=>{"exercise_id"=>"", "date"=>"2024-10-28", "repetitions"=>"3", "sets"=>"5"}, "calendar_id"=>"56", "id"=>"19"}
Calendar Load (0.8ms) SELECT "calendars".* FROM "calendars" WHERE "calendars"."id" = $1 LIMIT $2 [["id", 56], ["LIMIT", 1]]
↳ app/controllers/application_controller.rb:39:in `set_current_calendar'
CACHE Calendar Load (0.0ms) SELECT "calendars".* FROM "calendars" WHERE "calendars"."id" = $1 LIMIT $2 [["id", 56], ["LIMIT", 1]]
↳ app/controllers/schedules_controller.rb:92:in `set_calendar'
Set Calendar: #<Calendar id: 56, title: "あ", image: nil, calendar_color: nil, calendar_type: nil, user_type: "User", user_id: 4, created_at: "2024-09-30 08:55:52.401595000 +0000", updated_at: "2024-09-30 09:32:30.371458000 +0000">
Schedule Load (1.0ms) SELECT "schedules".* FROM "schedules" WHERE "schedules"."calendar_id" = $1 AND "schedules"."id" = $2 LIMIT $3 [["calendar_id", 56], ["id", 19], ["LIMIT", 1]]
↳ app/controllers/schedules_controller.rb:97:in `set_schedule'
Set Schedule: #<Schedule id: 19, calendar_id: 56, exercise_id: 2, date: "2024-10-28", repetitions: 3, duration: nil, created_at: "2024-10-18 07:15:31.853129000 +0000", updated_at: "2024-10-18 07:15:31.853129000 +0000", distance: nil, sets: 2>
UPDATE: Schedule ID: 19, Params: #<ActionController::Parameters {"_method"=>"put", "authenticity_token"=>"7jPhbgzmwxw8-KYzQd6DdgOrUey2yCzQXJSnYotYBJHCYqfZSAb848tE8RwFj9lBjezpywsuLJDf-I8ZznRN8Q", "schedule"=>{"exercise_id"=>"", "date"=>"2024-10-28", "repetitions"=>"3", "sets"=>"5"}, "controller"=>"schedules", "action"=>"update", "calendar_id"=>"56", "id"=>"19"} permitted: false>
Exercise ID is missing.
Rendering layout layouts/application.html.erb
Rendering schedules/edit.html.erb within layouts/application
Rendered schedules/edit.html.erb within layouts/application (Duration: 16.3ms | Allocations: 5216)
Rendered layout layouts/application.html.erb (Duration: 16.5ms | Allocations: 5292)
Completed 500 Internal Server Error in 27ms (ActiveRecord: 1.8ms | Allocations: 8079)
ActionView::Template::Error (undefined method `schedule_path' for #<ActionView::Base:0x0000000000ffc8>
recipient.public_send(method, *args, options)
^^^^^^^^^^^^):
1: <%= form_with(model: @schedule, local: true) do |form| %>
2: <div class="field">
3: <%= form.label :date %>
4: <%= form.date_field :date, value: @schedule.date %>
app/views/schedules/edit.html.erb:1
app/controllers/schedules_controller.rb:56:in `block (2 levels) in update'
app/controllers/schedules_controller.rb:55:in `update'
モーダルの初期化が影響してそうだと思ったのですが、そこからどうしたらいいのかわからない状態です。
valueの設定を確認するため、app/javascript/packs/schedule.jsに
valueはJS側でセットするのではなくerb上で<%= form.hidden_field :exercise_id, id: 'schedule_exercise_id', value: '入れたいexercise_id' %>
のようにセット出来るので調べてみてください
@calendar
や @schedule
にexercise_idを持たせているなら
<%= form.hidden_field :exercise_id, id: 'schedule_exercise_id', value: @schedule.exercise_id %>
でセット出来ます
app/views/schedules/_edit_modal.html.erbを
<div class="modal fade" id="editModal" tabindex="-1" aria-labelledby="editModalLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="editModalLabel">
Edit Schedule: <span id="exercise_name_display"></span>
</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<%= form_with model: [@calendar, @schedule], local: true, method: :put, id: "schedule-form" do |form| %>
**<%= form.hidden_field :exercise_id, id: 'schedule_exercise_id', value: @schedule.exercise_id %>**
<div class="mb-3">
<label for="schedule_date" class="form-label">Schedule Date</label>
<%= form.date_field :date, class: "form-control", id: "schedule_date", required: true %>
</div>
<div class="mb-3">
<label for="reps" class="form-label">Reps/Distance</label>
<%= form.number_field :repetitions, class: "form-control", id: "reps", min: 1, required: true %>
</div>
<div class="mb-3">
<label for="sets" class="form-label">Sets</label>
<%= form.number_field :sets, class: "form-control", id: "sets", min: 1, required: true %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<%= form.submit "Save changes", class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
</div>
</div>
このようにしましたが、変化ありませんでした。 他に何かないかとChatGPTに質問を投げてみたところ
function cleanupModal() {
document.getElementById("exercise_name_display").textContent = "";
const exerciseIdField = document.querySelector("#schedule-form input[name='schedule[exercise_id]']");
**if (exerciseIdField) exerciseIdField.value = "";**
document.body.classList.remove("modal-open");
const backdrop = document.querySelector(".modal-backdrop");
if (backdrop) backdrop.remove();
}
ここをコメントアウトもしくは削除したらどうかと出たため、試したところ、 https://gyazo.com/83b00bfcc6ca6eec337a783465aa1524 この状態でとまり、再読み込みをしたところ https://gyazo.com/7f09f25f65a1f998fa5ec14e744c3d72 このように、回数が編集できました。 どうやら、モーダルを開く際にリセットするようになっていたみたいです。
質問内容・実現したいこと 編集ボタンをクリックしたら、モーダルが切り替わり、日付や回数、セット数が変更できる。 その変更内容がカレンダーに反映される。
現状発生している問題・エラーメッセージ 編集ボタンをクリックしても、モーダルが切り替わらない。
該当のソースコード app/views/calendars/show.html.erb
スケジュール
<%= date %>
<% if schedules.any? %> <% schedules.each do |schedule| %>
<%= schedule.exercise.name %> <%= schedule.repetitions %> 回 × <%= schedule.sets %> セット
<% end %> <% else %>
この日にスケジュールはありません。
<% end %>
<% if schedules.count < 3 %>
<% else %>
これ以上スケジュールを追加できません。
<% end %>
Edit Schedule:
document.addEventListener("DOMContentLoaded", () => { const scheduleModalEl = document.getElementById("scheduleModal");
if (scheduleModalEl) { const scheduleModal = new bootstrap.Modal(scheduleModalEl); } else { console.error("Schedule modal element not found."); }
const scheduleModal = new bootstrap.Modal(scheduleModalEl); const scheduleForm = document.getElementById("schedule-form");
// 編集ボタンがクリックされたときの処理 const editButtons = document.querySelectorAll('.btn-outline-primary[data-bs-toggle="modal"]');
editButtons.forEach(button => { button.addEventListener('click', function () { const scheduleId = this.getAttribute('data-schedule-id'); const exerciseName = this.getAttribute('data-exercise-name'); const reps = this.getAttribute('data-reps'); const sets = this.getAttribute('data-sets'); const date = this.getAttribute('data-date');
});
// 初期化関数 function initializeModal() { scheduleModalEl.addEventListener("hidden.bs.modal", cleanupModal); }
// モーダルを開いてスケジュールを表示する関数 function openScheduleModal(date, calendarId) { fetch(
/calendars/${calendarId}/schedules?date=${date}
) .then((response) => { if (!response.ok) throw new Error("Failed to load schedule details."); return response.text(); }) .then((html) => { document.getElementById("schedule-details").innerHTML = html; scheduleModal.show(); registerAddButtonListener(); }) .catch((error) => console.error("Error loading schedule details:", error)); }// 追加ボタンのイベントを登録 function registerAddButtonListener() { const addScheduleBtn = document.getElementById("add-schedule-btn"); if (addScheduleBtn) { addScheduleBtn.addEventListener("click", () => { scheduleModal.hide(); window.location.href = "/exercises"; }); } }
// カレンダーの日付クリック処理 function registerCalendarClickListeners() { document.querySelectorAll(".calendar-date").forEach((element) => { element.addEventListener("click", (event) => { event.preventDefault(); const date = event.currentTarget.dataset.date; const calendarId = event.currentTarget.dataset.calendarId; openScheduleModal(date, calendarId); }); }); }
// フォームの送信処理 function handleFormSubmit(event) { event.preventDefault(); const formData = new FormData(scheduleForm);
}
// モーダル閉じるときの後処理 function cleanupModal() { if (scheduleForm) { scheduleForm.reset(); // フォームのリセット } else { console.warn("Schedule form not found."); }
}
// イベント登録 function registerEventListeners() { registerCalendarClickListeners(); if (scheduleForm) { scheduleForm.addEventListener("submit", handleFormSubmit); } }
// 初期化とイベント登録の実行 initializeModal(); registerEventListeners(); });
const scheduleModalEl = document.getElementById("scheduleModal"); console.log("scheduleModalEl:", scheduleModalEl); // デバッグ: モーダル取得確認 const editModalEl = document.getElementById("editModal");
if (scheduleModalEl) { const scheduleModal = new bootstrap.Modal(scheduleModalEl); console.log("Schedule modal initialized:", scheduleModal); // モーダルの初期化確認 } else { console.error("Schedule modal element not found."); }
const scheduleModal = new bootstrap.Modal(scheduleModalEl); const editModal = new bootstrap.Modal(editModalEl); const scheduleForm = document.getElementById("schedule-form"); console.log("scheduleForm:", scheduleForm); // フォーム取得確認