Closed kodamarisa closed 2 months ago
ファイル名はappなどを省略せずにどのディレクトリにあるのかわかるように記載をお願いします 現状だとファイルに何が書いてあるのかを読み解いたり、ログに書いてある内容を確認してどのような操作をしたのかを推測しないといけなくなっているので、どのファイルのどの処理が動いたときにエラーが出たのかがわかりやすいように書いていただけると助かります
すみませんでした。以後気をつけます。 下記にソースコードを上げ直しますので、確認をお願いします。 app/controllers/schedules_controller.rb
class SchedulesController < ApplicationController
before_action :set_calendar
before_action :set_schedule, only: [:show, :edit, :update, :destroy]
def new
@schedule = @calendar.schedules.build
@exercises = Exercise.all
respond_to do |format|
format.html # default behavior
format.json { render json: { html: render_to_string(partial: 'schedules/form', locals: { calendar: @calendar, schedule: @schedule, exercises: @exercises }) } }
end
end
def create
@schedule = @calendar.schedules.build(schedule_params)
if @schedule.save
respond_to do |format|
format.html { redirect_to calendar_path(@calendar), notice: 'Schedule was successfully created.' }
format.json { render json: { redirect_url: calendar_path(@calendar) }, status: :created }
end
else
@exercises = Exercise.all
respond_to do |format|
format.html { render :new }
format.json { render json: { html: render_to_string(partial: 'form', locals: { calendar: @calendar, schedule: @schedule, exercises: @exercises }) }, status: :unprocessable_entity }
end
end
end
def show
end
def edit
@exercises = Exercise.all
respond_to do |format|
format.html
format.json { render json: { html: render_to_string(partial: 'schedules/form', locals: { calendar: @calendar, schedule: @schedule, exercises: @exercises }) } }
end
end
def update
if @schedule.update(schedule_params)
respond_to do |format|
format.html { redirect_to calendar_path(@calendar), notice: 'Schedule was successfully updated.' }
format.json { render json: { redirect_url: calendar_path(@calendar) }, status: :ok }
end
else
@exercises = Exercise.all
respond_to do |format|
format.html { render :edit }
format.json { render json: { html: render_to_string(partial: 'form', locals: { calendar: @calendar, schedule: @schedule, exercises: @exercises }) }, status: :unprocessable_entity }
end
end
end
def destroy
@schedule.destroy
redirect_to calendar_path(@calendar), notice: 'Schedule was successfully deleted.'
end
private
def set_calendar
@calendar = Calendar.find_by(id: params[:calendar_id])
unless @calendar
render file: "#{Rails.root}/public/404.html", layout: false, status: :not_found
end
end
def set_schedule
@schedule = @calendar.schedules.find(params[:id])
end
def schedule_params
params.require(:schedule).permit(:date, :exercise_id, :repetitions, :duration)
end
end
app/javascript/packs/schedule.js
document.addEventListener("DOMContentLoaded", () => {
const modal = document.getElementById("schedule-modal");
const span = document.getElementsByClassName("close")[0];
function showModal(html) {
document.getElementById("schedule-details").innerHTML = html;
modal.style.display = "block";
setupFormSubmission();
}
document.querySelectorAll(".calendar-date").forEach(element => {
element.addEventListener("click", (event) => {
event.preventDefault();
const date = event.currentTarget.dataset.date;
const calendarId = event.currentTarget.dataset.calendarId;
fetch(`/calendars/${calendarId}/schedules/new?date=${date}`, {
headers: {
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => showModal(data.html));
});
});
document.querySelectorAll(".edit-schedule").forEach(element => {
element.addEventListener("click", (event) => {
event.preventDefault();
const scheduleId = event.currentTarget.dataset.scheduleId;
const calendarId = event.currentTarget.dataset.calendarId;
fetch(`/calendars/${calendarId}/schedules/${scheduleId}/edit`, {
headers: {
'Accept': 'application/json'
}
})
.then(response => response.json())
.then(data => showModal(data.html));
});
});
span.onclick = function() {
modal.style.display = "none";
}
window.onclick = function(event) {
if (event.target == modal) {
modal.style.display = "none";
}
}
function setupFormSubmission() {
const form = document.getElementById("schedule_form");
if (!form) return;
form.addEventListener("submit", (event) => {
event.preventDefault();
const formData = new FormData(form);
fetch(form.action, {
method: 'POST',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
}
})
.then(response => response.json())
.then(data => {
if (data.redirect_url) {
window.location.href = data.redirect_url;
} else {
showModal(data.html);
}
});
});
}
});
app/views/schedules/new.html.erb
<div id="schedule-modal" class="modal">
<div class="modal-content">
<span class="close">×</span>
<div id="schedule-details"></div>
</div>
</div>
app/views/schedules/edit.html.erb
<div id="schedule-modal" class="modal">
<div class="modal-content">
<span class="close">×</span>
<div id="schedule-details">
<%= render partial: 'form', locals: { calendar: @calendar, schedule: @schedule, exercises: @exercises } %>
</div>
</div>
</div>
app/views/schedules/_form.html.erb
<%= form_with(model: [calendar, schedule], local: false, html: { id: 'schedule_form' }) do |form| %>
<% if schedule.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(schedule.errors.count, "error") %> prohibited this schedule from being saved:</h2>
<ul>
<% schedule.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= form.label :date %>
<%= form.date_field :date %>
</div>
<div class="field">
<%= form.label :exercise_id, "Exercise" %>
<%= form.collection_select :exercise_id, exercises, :id, :name, prompt: "Choose an exercise" %>
</div>
<div class="field">
<%= form.label :repetitions %>
<%= form.number_field :repetitions %>
</div>
<div class="field">
<%= form.label :duration, "Duration (seconds)" %>
<%= form.number_field :duration %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
app/views/schedules/_schedule.html.erb
<div class="schedule">
<p>Date: <time datetime="<%= schedule.date %>"><%= schedule.date %></time></p>
<%= link_to 'Edit', edit_calendar_schedule_path(schedule.calendar, schedule), class: "btn btn-secondary edit-schedule", data: { schedule_id: schedule.id, calendar_id: schedule.calendar.id } %>
<%= link_to 'Delete', schedule, method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-danger" %>
</div>
各ファイルはこの状態になります。
ありがとうございます! これとか関係ありそうですかね? https://stackoverflow.com/questions/7078439/rails-render-to-string-giving-errors-with-partial-view
ありがとうございます! app/controllers/schedules_controller.rbのnewアクション部分を
def new
@schedule = @calendar.schedules.build
@exercises = Exercise.all
respond_to do |format|
format.html
format.json { render json: { html: render_to_string(partial: 'schedules/form', locals: { calendar: @calendar, schedule: @schedule, exercises: @exercises }) } }
end
end
コレから
def new
@schedule = @calendar.schedules.build
@exercises = Exercise.all
logger.debug "Rendering new schedule form"
logger.debug "Calendar: #{@calendar.inspect}"
logger.debug "Schedule: #{@schedule.inspect}"
logger.debug "Exercises: #{@exercises.inspect}"
respond_to do |format|
format.html # default behavior
format.json { render json: { html: render_to_string(partial: 'schedules/form', formats: [:html], locals: { calendar: @calendar, schedule: @schedule, exercises: @exercises }) } }
end
end
この形に変更し、formats: [:html]このコードを該当部分に挿入したらモーダルが表示されるようになりました! コレは、htmlへのレンダリングがうまくいってないために起こっていたエラーってことでいいんですかね?
詳しくはわかりませんが、render jsonで探してたのでhtmlの拡張子がついているファイル探してくれなかったのかなって感じですかね
質問内容・実現したいこと スケジュール機能をモーダル形式で表示できるようにし、スケジュールの作成時に必要な情報が足りていない場合に、同じモーダル形式でのスケジュール機能にエラー文を足してわかりやすくしたい
現状発生している問題・エラーメッセージ カレンダーをクリックしてもスケジュール機能が表示できずターミナルでは
ActionView::MissingTemplate (Missing partial schedules/_form with {:locale=>[:en], :formats=>[:json], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :jbuilder]}. Searched in:
app/controllers/schedules_controller.rb:11:in
block (2 levels) in new' app/controllers/schedules_controller.rb:9:in
new'<%= form_with(model: [calendar, schedule], local: false, html: { id: 'schedule_form' }) do |form| %> <% if schedule.errors.any? %>
<%= pluralize(schedule.errors.count, "error") %> prohibited this schedule from being saved:
<% schedule.errors.full_messages.each do |message| %>- <%= message %>
<% end %>
<% end %>
<% end %>
Date:
<%= link_to 'Edit', edit_calendar_schedule_path(schedule.calendar, schedule), class: "btn btn-secondary edit-schedule", data: { schedule_id: schedule.id, calendar_id: schedule.calendar.id } %> <%= link_to 'Delete', schedule, method: :delete, data: { confirm: 'Are you sure?' }, class: "btn btn-danger" %>class SchedulesController < ApplicationController before_action :set_calendar before_action :set_schedule, only: [:show, :edit, :update, :destroy]
def new @schedule = @calendar.schedules.build @exercises = Exercise.all
end
def create @schedule = @calendar.schedules.build(schedule_params)
end
def show end
def edit @exercises = Exercise.all respond_to do |format| format.html format.json { render json: { html: render_to_string(partial: 'schedules/form', locals: { calendar: @calendar, schedule: @schedule, exercises: @exercises }) } } end end
def update if @schedule.update(schedule_params) respond_to do |format| format.html { redirect_to calendar_path(@calendar), notice: 'Schedule was successfully updated.' } format.json { render json: { redirect_url: calendar_path(@calendar) }, status: :ok } end else @exercises = Exercise.all respond_to do |format| format.html { render :edit } format.json { render json: { html: render_to_string(partial: 'form', locals: { calendar: @calendar, schedule: @schedule, exercises: @exercises }) }, status: :unprocessable_entity } end end end
def destroy @schedule.destroy redirect_to calendar_path(@calendar), notice: 'Schedule was successfully deleted.' end
private
def set_calendar @calendar = Calendar.find_by(id: params[:calendar_id]) unless @calendar render file: "#{Rails.root}/public/404.html", layout: false, status: :not_found end end
def set_schedule @schedule = @calendar.schedules.find(params[:id]) end
def schedule_params params.require(:schedule).permit(:date, :exercise_id, :repetitions, :duration) end end
document.addEventListener("DOMContentLoaded", () => { const modal = document.getElementById("schedule-modal"); const span = document.getElementsByClassName("close")[0];
function showModal(html) { document.getElementById("schedule-details").innerHTML = html; modal.style.display = "block"; setupFormSubmission(); }
document.querySelectorAll(".calendar-date").forEach(element => { element.addEventListener("click", (event) => { event.preventDefault(); const date = event.currentTarget.dataset.date; const calendarId = event.currentTarget.dataset.calendarId; fetch(
/calendars/${calendarId}/schedules/new?date=${date}
, { headers: { 'Accept': 'application/json' } }) .then(response => response.json()) .then(data => showModal(data.html)); }); });document.querySelectorAll(".edit-schedule").forEach(element => { element.addEventListener("click", (event) => { event.preventDefault(); const scheduleId = event.currentTarget.dataset.scheduleId; const calendarId = event.currentTarget.dataset.calendarId; fetch(
/calendars/${calendarId}/schedules/${scheduleId}/edit
, { headers: { 'Accept': 'application/json' } }) .then(response => response.json()) .then(data => showModal(data.html)); }); });span.onclick = function() { modal.style.display = "none"; }
window.onclick = function(event) { if (event.target == modal) { modal.style.display = "none"; } }
function setupFormSubmission() { const form = document.getElementById("schedule_form"); if (!form) return; form.addEventListener("submit", (event) => { event.preventDefault(); const formData = new FormData(form);
} });