はじめに
今回は、Railsでの予約システムにおける非同期スロット更新の実装方法と、発生したエラーの解決方法について共有します。
問題点
予約システムの開発中に、日付を変更するたびにスロット情報を非同期で更新しようとしましたが、以下のエラーが発生しました。
ActiveRecord::RecordNotFound - Couldn't find Company with 'id'=undefined:
app/controllers/reservations_controller.rb:207:in `update_slots'
解決方法
エラーの原因は、JavaScriptでcompany_id
が正しく取得されず、リクエストにundefined
が渡されていたことです。以下の手順で解決しました。
ビューの修正
company_id
を含むデータ属性を日付入力フィールドに追加します。
<%= form.date_field :date, id: 'for_customer_index_date_field', value: @date.strftime('%Y-%m-%d'), class: 'form-control', data: { company_id: @company.id } %> <!-- ここでdata-company-id属性を追加 -->
JavaScriptの修正
データ属性からcompany_id
を取得し、リクエストに含めるようにします。
document.addEventListener('turbo:load', function() {
const dateField = document.querySelector('#for_customer_index_date_field');
if (dateField) {
const companyId = dateField.dataset.companyId;
const scheduleTitle = document.querySelector('.page-index');
let companyName = '';
if (scheduleTitle && scheduleTitle.textContent) {
const match = scheduleTitle.textContent.match(/^(.*?)の/);
if (match) {
companyName = match[1];
}
}
const debouncedFetch = debounce(function(date) {
fetch(`/reservations/update_slots?date=${date}&company_id=${companyId}`, { // company_idをリクエストに含める
headers: {
'Accept': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
'X-CSRF-Token': document.querySelector("[name='csrf-token']").content
},
credentials: 'include'
})
.then(response => response.json())
.then(data => {
if (data && data.services && data.time_slots !== undefined) {
updateTable({ ...data, date });
} else {
console.error("Invalid data format received:", data);
}
})
.catch(error => console.error('Error fetching data:', error));
}, 500);
dateField.addEventListener('input', function() {
debouncedFetch(this.value);
});
}
});
コントローラーの修正
update_slots
アクションでcompany_id
を正しく取得し、処理を行います。
def update_slots
date = params[:date]
@date = Date.parse(date)
@company = Company.find(params[:company_id])
@time_slots = generate_time_slots(@company)
@non_business_day = ScheduleService.is_non_business_day?(@company, @date)
@services = @company.services
@service_availability = ScheduleService.calculate_availability(@company, @date, @services, @time_slots)
response_data = {
services: @services.map { |service|
{
name: service.name,
duration: format_duration(service.duration),
time_slots: @time_slots.map { |slot| { availability: @service_availability.dig(service.id, slot) || '-' } },
}
},
time_slots: @time_slots,
non_business_day: @non_business_day
}
render json: response_data
end