Ruby on Rails の条件付きレンダリングが機能しない
概要
このモーダルを表示すると予期しない動作が発生します。
<% if @show_modal %>
<%= render 'modal' %>
<% end %>
<div id="scanQrCodeModal">
<h1>Scan QR Codes</h1>
<div class="section">
<div id="my-qr-reader"></div>
</div>
</div>
インスタンス変数 @show_modal は、attences_controller.rb のこのメソッドから生成され、my_student_course.size > 1 の場合を除いて、すべてが期待どおりに動作します。
def mark_attendance
token = params[:encoded_token]
# Ensure the token is provided
if token.blank?
render json: { error: "Token is missing" }, status: :unprocessable_entity
return
end
begin
#decode jwt token
secret_key = Rails.application.credentials.secret_key_base
payload = JWT.decode(token, secret_key, true, algorithm: "HS256")[0]
lecturer_id = payload["lecturer_id"]
lecturer = Lecturer.find_by(id: lecturer_id)
if lecturer
my_student_course = lecturer.lecturer_units.flat_map(&:students_courses).uniq.select { |course| course.student_id == current_student.id }
if my_student_course.size > 1
@show_modal = true
@students_attendance_courses = my_student_course
puts @students_attendance_courses
# Render a pop-up page with a list of results and radio buttons for selection
else
# If there is only one result or none, proceed with the first result
@student_course = my_student_course
my_student_course_id = @student_course.first&.id
end
create_attendance(my_student_course_id)
else
render json: { error: "Lecturer not found for the given lecturer_id" }, status: :unprocessable_entity
end
rescue JWT::DecodeError => e
render json: { error: "Invalid token format" }, status: :unprocessable_entity
end
end
これは私のブートストラップモーダルです:
<!-- Button trigger modal -->
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalLabel">Modal title</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<% if @show_modal %>
<div id="modal">
<!-- Use @students_attendance_courses to render the list -->
<% @students_attendance_courses.each do |course| %>
<!-- Rendering course details as needed -->
<%= course.id %>
<% end %>
</div>
<% else %>
<%= "No modal to show" %>
<% end %>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var myModal = new bootstrap.Modal(document.getElementById('exampleModal'));
myModal.show();
});
</script>
ページ読み込み時に表示されるモーダルが false の場合にレンダリングするように条件レンダリングを変更しました。
<% if !@show_modal %>
<%= render 'modal' %>
<% end %>
<div id="scanQrCodeModal">
<h1>Scan QR Codes</h1>
<div class="section">
<div id="my-qr-reader"></div>
</div>
</div>
これがマーク出席をトリガーする方法です
function domReady(fn) {
if (
document.readyState === "complete" ||
document.readyState === "interactive"
) {
setTimeout(fn, 1000);
} else {
document.addEventListener("DOMContentLoaded", fn);
}
}
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;
function sendPostRequest(encodedToken, csrfToken) {
const currentUrl = window.location.href;
// Replace "/scan" with "/mark_attendance" in the URL
const newUrl = currentUrl.replace('/scan', '/mark_attendance');
fetch(newUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-Token': csrfToken,
},
body: JSON.stringify({ encoded_token: encodedToken }),
})
.then(response => {
if (response.redirected) {
// Handling redirect manually
window.location.href = response.url;
} else {
return response.json();
}
})
.catch(error => {
console.error('Error:', error);
});
}
domReady(function () {
// If found your QR code
function onScanSuccess(decodeText, decodeResult) {
alert("Your QR code is: " + decodeText, decodeResult);
// Fetch CSRF token from the meta tag
const csrfToken = document.querySelector('meta[name="csrf-token"]').content;
// Send a POST request to create attendance
sendPostRequest(decodeText, csrfToken);
}
let htmlscanner = new Html5QrcodeScanner(
"my-qr-reader",
{ fps: 10,
qrbox: { width: 250, height: 250 },
supportedScanTypes: [Html5QrcodeScanType.SCAN_TYPE_CAMERA, Html5QrcodeScanType.SCAN_TYPE_FILE] }
);
htmlscanner.render(onScanSuccess);
});
解決策
条件を if !@show_modal によってモーダルが表示されるように変更すると、ビューのレンダリング時に @show_modal が false または nil になる可能性があることが示唆されます。これは、コントローラー アクションが @show_modal を期待どおりに設定していないこと、または @show_modal が設定されていない別の要求サイクルでビューがレンダリングされていることが原因である可能性があります。
したがって、条件が正しく設定されていても問題が解決しない場合は、モーダルを表示するための JS が @show_modal で条件付けされていないことが問題である可能性があります。つまり、ページが読み込まれるたびに実行されるため、次のようにする必要があります。 @show_modal に関連付けます。 これを行うには、次のようなことを試すことができます。
<% if @show_modal %>
<%= render 'modal' %>
<script>
document.addEventListener('DOMContentLoaded', function() {
var myModal = new bootstrap.Modal(document.getElementById('exampleModal'));
myModal.show();
});
</script>
<% end %>