fukasawamoe / yoriyoi

1 stars 0 forks source link

achiementのグラフのajax以外の実装ができました #83

Closed fukasawamoe closed 10 months ago

fukasawamoe commented 10 months ago

ajax化がわからないのでご助言いただけると幸いです。 ajax化実現のためにやったこと 各ボタンにremote: trueを表記、idを設定

+app/javascript/custom/steps.js

console.log("HelloWorld")

document.addEventListener("DOMContentLoaded", function() {
  var updateButton = document.getElementById("updateButton");
  if (updateButton) {
    updateButton.addEventListener("click", function() {
      var stepId = this.dataset.stepId; // ボタンのdata-step-id属性からステップIDを取得
      var xhr = new XMLHttpRequest();
      xhr.open("POST", "/steps/" + stepId + "/add_day_check"); // URLにステップIDを追加
      xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
      xhr.send();
    });
  }
});

+/app/views/steps/add_day_check.js.erb

console.log("Hello world")
document.getElementById("achievement").innerHTML = "<%= j render 'achievement', step: @step %>";

steps_controller.rb

      respond_to do |format|
        format.js
        format.html { redirect_to home_index_path }
      end
kenchasonakai commented 10 months ago

format.jsはRails7系のデフォルトでは使えないのでturbo_streamを使った方が良いかなと思います。

スクリーンショット等を使用して画面のどのボタンを押したら、どこのコントローラーのどのアクションで処理をして非同期処理をしたいのか教えてください

fukasawamoe commented 10 months ago

コメントありがとうございます。 承知しました。

現状は、週のボタンを押下するとsteps_controllerのupdate_multipleに飛び、 stepのidから紐づいたachievementのday_check(*配列型 月-日の数値が入り、sizeメソッドで要素の数を数えて週に行った回数をカウントする)に登録していく流れです(すでに配列にある曜日が選択された場合は配列から削除を行う)

以下、ボタン押下後にachievementが非同期通信されない様子 Image from Gyazo

そのため、steps_controllerのadd_day_checkの@.step.achievement.save!の下あたりにどうにか上手く書けないかと考えています。 ちなみに、週のボタンの処理に関しましてはすでにTurboStreamを使用しており、goals/show.html.erbにて、<%= turbo_frame_tag step do %>を組み込み非同期通信にしています。(Achievementのグラフにも適用しようとしたのですがこちらの場合は変化なしで更新されませんでした)

現在はturbo_streamで実装し直そうとしており、Achievementモデルが更新される際にhome/_achievement.html.erbをレンダリングするようにしたいと考えています。

#Achievement.rb
class Achievement < ApplicationRecord
  belongs_to :step

  def broadcast_achievement(current_user)
    broadcast_replace_to("achievements", partial: "home/achievement", locals: { steps: Step.where(user_id: current_user.id) })
  end
end
#steps_controllerより一部抜粋
class StepsController < ApplicationController

  def add_day_check
    @step = Step.find_by(id: params[:id], user_id: current_user.id)
    if @step && @step.achievement
      target_day = params[:day].to_i # この値はリクエストのパラメータから取得
      array_day_check = @step.achievement.day_check
      if array_day_check.include?(target_day)
        array_day_check.delete(target_day)
      else
        array_day_check<<target_day
      end
      @step.achievement.save!
      @step.achievement.broadcast_achievement(current_user)
      redirect_to home_index_path
    end
  end
end
kenchasonakai commented 10 months ago

broadcast使わないで良いと思いますよ 下記記事のイメージでコントローラーに対応するadd_day_check.turbo_stream.erbファイルを作ってあげてそこでHTMLを置き換える処理を書いてあげる感じです(redirect_toも消します)

https://zenn.dev/takeyuwebinc/articles/9f63f07fe5f4e0#step-2.-%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0%E9%80%81%E4%BF%A1%E3%82%92%E3%83%88%E3%83%AA%E3%82%AC%E3%83%BC%E3%81%AB%E3%81%97%E3%81%9F-2-%E7%AE%87%E6%89%80%E4%BB%A5%E4%B8%8A%E3%81%AE%E6%9B%B4%E6%96%B0%E3%82%92%E5%AE%9F%E7%8F%BE

fukasawamoe commented 10 months ago

ありがとうございます! ご提示いただいた内容で実装してみましたところ実装できました。 ~~ですが、グラフの挙動は正しく動くのですが ボタンの連動がうまくいっておらず、おかしな挙動をしてしまいます。~~

説明が難しいので以下にgifを貼りますのでご確認いただければ幸いです。 Image from Gyazo

問題解決のために行ったこと 修正前の<%= turbo_frame_tag step do %>を使用していた際にも同じような事象が起きましたが、 その時はdivタグの前に設置することでこれを回避することができていました。 (そのため以下のコードでも

#(1)
のように分けています) 現在は

#goals/show.html.erb
        <% steps.each do |step| %>
          <% action = step.action %>
          <% times_set = step.times_set %>
          <% unless action.blank? && times_set.blank? %>
            <li><i class="fa-solid fa-fire" style="color: #f26845;"></i>  <%= action %>を週<%= times_set %>回行う</li>
            <div id="achievement_button"> #(1)
              <div class='flex flex-wrap'> #(1)を削除してこの部分にid="achievement_button"を設置するなどしました。
                <% (0..6).each do |day| %>
                  <% if step.achievement.day_check.include?(day) %>
                    <%= render "achievements/on_button", day: day, step: step %>
                  <% else %>
                    <%= render "achievements/off_button", day: day, step: step %>
                  <% end %>
                <% end %>
              </div>
            </div>
            <% all_blank = false %>
          <% end %>
        <% end %>

divタグの部分をずらすなど行なったのですが直りません(コード内の#参照)

#steps/add_day_check.turbo_stream.erb
<%= turbo_stream.update "achievement_button" do %>
  <div class='flex flex-wrap'>
    <% (0..6).each do |day| %>
      <% if @step.achievement.day_check.include?(day) %>
        <%= render "achievements/on_button", day: day, step: @step %>
      <% else %>
        <%= render "achievements/off_button", day: day, step: @step %>
      <% end %>
    <% end %>
  </div>
<% end %>

<%= turbo_stream.update "achievement_graph" do %>
  <% @steps.each do |step| %>
    <div class="grid grid-cols-3 gap-10">
      <% if step.action.present?%>
        <div id="achievement-<%= step.id %>" class="achievement">
          <p><%= step.action %></p>
          <% calculated_value1 = (((step.achievement.day_check.size*0.1)/(step.times_set*0.1))* 100).round %>
          <div class="radial-progress bg-red-100 text-primary-content border-4 border-primary" style="--value:<%= calculated_value1 %>; --size:12rem; --thickness: 2rem;" role="progressbar"><%= calculated_value1 %>%</div>
        </div>
      <% end %>
    </div>
  <% end %>
<% end %>
fukasawamoe commented 10 months ago

すみません、以下のようにすることで解決しました...! ご確認よろしくお願いいたします! Image from Gyazo

goals/show.html.erb

        <div id="achievement_button">
          <% steps.each do |step| %>
            <% action = step.action %>
            <% times_set = step.times_set %>
            <% unless action.blank? && times_set.blank? %>
              <li><i class="fa-solid fa-fire" style="color: #f26845;"></i>  <%= action %>を週<%= times_set %>回行う</li>
              <div class='flex flex-wrap'>
                <% (0..6).each do |day| %>
                  <% if step.achievement.day_check.include?(day) %>
                    <%= render "achievements/on_button", day: day, step: step %>
                  <% else %>
                    <%= render "achievements/off_button", day: day, step: step %>
                  <% end %>
                <% end %>
              </div>
              <% all_blank = false %>
            <% end %>
          <% end %>

steps/add_day_check.turbo_stream.erb

<%= turbo_stream.update "achievement_button" do %>
  <% @steps.each do |step| %>
    <% action = step.action %>
    <% times_set = step.times_set %>
    <% unless action.blank? && times_set.blank? %>
      <li><i class="fa-solid fa-fire" style="color: #f26845;"></i>  <%= action %>を週<%= times_set %>回行う</li>
      <div class='flex flex-wrap'>
        <% (0..6).each do |day| %>
          <% if step.achievement.day_check.include?(day) %>
            <%= render "achievements/on_button", day: day, step: step %>
          <% else %>
            <%= render "achievements/off_button", day: day, step: step %>
          <% end %>
        <% end %>
      </div>
      <% all_blank = false %>
    <% end %>
  <% end %>
<% end %>

<%= turbo_stream.update "achievement_graph" do %>
  <% @steps.each do |step| %>
    <div class="grid grid-cols-3 gap-10">
      <% if step.action.present?%>
        <div id="achievement-<%= step.id %>" class="achievement">
          <p><%= step.action %></p>
          <% calculated_value1 = (((step.achievement.day_check.size*0.1)/(step.times_set*0.1))* 100).round %>
          <div class="radial-progress bg-red-100 text-primary-content border-4 border-primary" style="--value:<%= calculated_value1 %>; --size:12rem; --thickness: 2rem;" role="progressbar"><%= calculated_value1 %>%</div>
        </div>
      <% end %>
    </div>
  <% end %>
<% end %>