kodamarisa / osinotameni_yasetai

0 stars 0 forks source link

スケジュール機能でのエラー #40

Closed kodamarisa closed 2 months ago

kodamarisa commented 3 months ago

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:innew'

この文章が出ている。

- どの処理までうまく動いているのか
モーダルの作成がうまくいってないので、スケジュールの作成ができない状態です。

- 該当のソースコード
schedules/_form.html.erb

<%= 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 %>

<%= form.label :date %> <%= form.date_field :date %>
<%= form.label :exercise_id, "Exercise" %> <%= form.collection_select :exercise_id, exercises, :id, :name, prompt: "Choose an exercise" %>
<%= form.label :repetitions %> <%= form.number_field :repetitions %>
<%= form.label :duration, "Duration (seconds)" %> <%= form.number_field :duration %>
<%= form.submit %>

<% end %>

schedules/new.html.erb
schedules/edit.html.erb
schedules/_schedule.html.erb

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" %>
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

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);
    }
  });
});

} });



- エラーから考えられる原因
ChatGPTにエラー分を聞くとschedules/_form.html.erbが見つけられないせいと出てきました。
- 試したこと
スペルの確認と他にエラーの原因がないかを確認しましたが、よくわからない状態です。
kenchasonakai commented 3 months ago

ファイル名はappなどを省略せずにどのディレクトリにあるのかわかるように記載をお願いします 現状だとファイルに何が書いてあるのかを読み解いたり、ログに書いてある内容を確認してどのような操作をしたのかを推測しないといけなくなっているので、どのファイルのどの処理が動いたときにエラーが出たのかがわかりやすいように書いていただけると助かります

https://blog.jnito.com/entry/2020/04/17/072343

kodamarisa commented 3 months ago

すみませんでした。以後気をつけます。 下記にソースコードを上げ直しますので、確認をお願いします。 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">&times;</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">&times;</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>

各ファイルはこの状態になります。

kenchasonakai commented 3 months ago

ありがとうございます! これとか関係ありそうですかね? https://stackoverflow.com/questions/7078439/rails-render-to-string-giving-errors-with-partial-view

kodamarisa commented 3 months ago

ありがとうございます! 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へのレンダリングがうまくいってないために起こっていたエラーってことでいいんですかね?

kenchasonakai commented 3 months ago

詳しくはわかりませんが、render jsonで探してたのでhtmlの拡張子がついているファイル探してくれなかったのかなって感じですかね