Techioz Blog

Rails での FullCalendar の実装

概要

RoR プロジェクトに FullCalendar を実装していますが、行を更新しようとすると次のエラーが発生しました。

イベントをクリックしたときに行を更新するための Ajax 呼び出しは次のとおりです。

$.ajax({
                        type: 'PATCH', // Use PATCH or PUT depending on your Rails routes
                        url: '/events/' + eventId, // Adjust the URL to your Rails route

                        data: {
                            event: {
                                title: 'updatedTitle',
                                start_date: 'updatedStartDate',
                                end_date: 'updatedEndDate',
                                description: 'updatedDescription'
                            }
                        },
                        beforeSend: function(xhr) {
                            xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
                        },
                        success: function(response) {
                            if (response.status === 'success') {
                                // Update the event data in FullCalendar
                                arg.event.setProp('title', updatedTitle);
                                arg.event.setStart(updatedStartDate);
                                arg.event.setEnd(updatedEndDate);
                                arg.event.setExtendedProp('description', updatedDescription);

                                // Close the modal
                                $('#eventModal').modal('hide');

                                // Display a success message (you can use Swal or other methods)
                                Swal.fire({
                                    text: 'Event updated successfully',
                                    icon: 'success',
                                    buttonsStyling: false,
                                    confirmButtonText: 'Ok, got it!',
                                    customClass: {
                                        confirmButton: 'btn btn-primary',
                                    }
                                });
                            } else {
                                // Handle the case where the update failed
                                Swal.fire({
                                    text: 'Event update failed: ' + response.message,
                                    icon: 'error',
                                    buttonsStyling: false,
                                    confirmButtonText: 'Ok, got it!',
                                    customClass: {
                                        confirmButton: 'btn btn-primary',
                                    }
                                });
                            }
                        },
                        error: function(error) {
                            console.log('AJAX request to Rails failed.');
                            console.log(error)
                        },
                    });

イベント ID を console.log に記録しましたが、正しく実装されています (値は 76)。 Ajax 呼び出しで使用される URL が URL: ‘/events/’ である理由がわかりません。

これが私のroutes.rbファイルです。

Rails.application.routes.draw do
  resources :telephones


  get 'home/index'
  resources :tickets
  resources :imprimantes
  resources :voitures
  resources :telephones
  resources :events

  resources :events do
    collection do
    post 'import_ics'
    get 'export_ics'
  end
end

  # Define a route for updating events using PATCH
  patch '/events/:id', to: 'events#update', as: 'update_event'

  resources :google_calendar, only: [:index, :create, :update, :destroy]


  root 'home#index'

  # Defines the root path route ("/")
  # root "posts#index"
end

そして更新機能:

def update
      @event = Event.find(params[:id])
      if @event.update(event_params)
        redirect_to events_path
      else
        render 'edit'
      end


 def event_params
  params.require(:event).permit(:title, :start_date, :end_date, :description)
end
    end

私は何を取りこぼしたか ?

編集:Railsコンソールログ

    Started PATCH "/events/68" for 127.0.0.1 at 2023-11-14 23:55:04 +0100
Processing by EventsController#update as */*
  Parameters: {"event"=>{"title"=>"updatedTitle", "start_date"=>"updatedStartDate", "end_date"=>"updatedEndDate", "description"=>"updatedDescription"}, "id"=>"68"}
  Event Load (0.5ms)  SELECT `events`.* FROM `events` WHERE `events`.`id` = 68 LIMIT 1
  ↳ app/controllers/events_controller.rb:42:in `update'
  TRANSACTION (15.7ms)  BEGIN
  ↳ app/controllers/events_controller.rb:43:in `update'
  Event Update (11.3ms)  UPDATE `events` SET `events`.`title` = 'updatedTitle', `events`.`start_date` = NULL, `events`.`end_date` = NULL, `events`.`description` = 'updatedDescription', `events`.`updated_at` = '2023-11-14 22:55:04.903524' WHERE `events`.`id` = 68
  ↳ app/controllers/events_controller.rb:43:in `update'
  TRANSACTION (8.0ms)  COMMIT
  ↳ app/controllers/events_controller.rb:43:in `update'
Redirected to http://127.0.0.1:3000/events
Completed 302 Found in 61ms (ActiveRecord: 35.5ms | Allocations: 4141)


Started PATCH "/events" for 127.0.0.1 at 2023-11-14 23:55:04 +0100
  
ActionController::RoutingError (No route matches [PATCH] "/events"):
  

解決策

Rails ログによると、JS が有効なリクエストを発行し、レコードを更新しているようです。問題は、更新が成功するとコントローラーで events_path にリダイレクトされるということです

if @event.update(event_params)
  redirect_to events_path
else
  render 'edit'
end

リクエストの MIME タイプを区別するロジックを追加してみてはいかがでしょうか?

何かのようなもの:

def update
  @event = Event.find(params[:id])

  respond_to do |format|
    if @event.update(event_params)
      format.html { redirect_to events_path }
      format.json { render json: { status: :success } }
    else
      format.html { render 'edit' }
      format.json { render json: { status: :unprocessable_entity } }
    end
  end
end

ソースへのリンク Mime が応答する

また、ajax 呼び出しに Accept ヘッダーを追加する必要があります。 ajax 呼び出しは次のようになります。

$.ajax({
  type: 'PATCH',
  url: '/events/1',
  headers: {
    Accept: "application/json"
  },
  data: {
    event: {
      title: 'new_title'
    }
  },
  beforeSend: function(xhr) {
    xhr.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'))
  },
  success: function(response) {
    console.log(response)
    // Handle your response
  },
  error: function(response) {
    console.error(response)
    // Handle your error
  }
})