2

I'm building an events platform with Devise gem & Rails 6.1. I'm having trouble with a small RSVP functionality.

When a non-login user click "Attend" button, it redirect the user to sign-in and once this is done the user is redirect back to the previous page. HOWEVER user has to click again "Attend" button.

I want the user redirect back and ALSO complete the create action ( POST action )

I managed to do the redirect work fine, but the user would have to click again on the "Attend" button which I do not want. I've searched the entire internet but none of the solutions worked. The closet solution I've found is from this blog https://blog.justinthiele.com/retaining-form-data-through-a-login-process-a/ which I tried to apply on my app but without success.

I would think that something is missing in the after_sign_in_path_for method.

Any help would be appreciated.

UPDATE!

After debugging, I changed a bit the way I'm overriding Devise. I feel I'm very close to the solution but can't figure it out what I'm missing.

attendee_controller.rb

    def create
      if !current_user
        # Store the data in the session so we can retrieve it after login
        session[:attendee] = params
        # Redirect the user to register/login
        redirect_to user_session_path
      else
        @attendee = current_user.attendees.build({event_id: params[:id]})

        respond_to do |format|
          AttendeeMailer.with(event: @attendee).notify_event_creator.deliver_now

          if @attendee.save
            format.html { redirect_to @attendee.event, notice: "You have successfully registered for the event!" }
            format.json { render :show, status: :created, location: @attendee }
          else
            format.html { render :new, status: :unprocessable_entity }
            format.json { render json: @attendee.errors, status: :unprocessable_entity }
          end
        end
      end
    end 

app\controllers\users\sessions_controller.rb (user_session_path)

   protected

  def after_sign_in_path_for(resource_or_scope)
    if session[:attendee].present?
      new_attributes = session[:attendee]
      previous_url = session[:previous_url] #defined in the show method from the events controller.

      @attendee = current_user.attendees.create({event_id: new_attributes[:id]})

      #clear session
      session[:attendee] = nil
      session[:previous_url] = nil
     
      previous_url
  else
    #if there is not temp attendee in the session proceed as normal
      super
    end
  end

events_controller.rb

def show 
 session[:previous_url] = request.fullpath
end

routes.rb

  devise_for :users, controllers: { sessions: "users/sessions" }
  resources :events do
    post :attendee, to: 'attendees#create', on: :member
    post :unattend, to: 'attendees#destroy', on: :member
  end

In Views, views\events\show.html.erb

<%= button_to 'Attend Now', attendee_event_path(@event), class:"btn btn-success btn-lg" %>

Natblow
  • 53
  • 1
  • 8
  • 1
    Try adding some logging to e.g. `store_user_location!` and `after_sign_in_path_for`. `Rails.logger` writes to `log/development.log`. Please understand my sympathy when I say: I think the computer is doing exactly what you told it to :) Some logging should help. – Jared Beck Mar 09 '22 at 03:41
  • 1
    Thank you, @JaredBeck . I wasn't very familiar with Rails.logger but will definetly use it. For now I have used pry gem, and it seems that the method `after_sign_in_path_for` was never overriding Devise default method, so I changed the way I coded it. Now I just updated my question. – Natblow Mar 09 '22 at 20:42

1 Answers1

1

Found the solution ! There is actually a gem called repost, that helps you redirect to a POST action. I implemented it in my solution.

Here is the whole technique I applied. To redirect after sign-in and then complete the POST action when the login was successful:

First, I create a session session[:previous_url] for later on to be used to redirect back here.

  def show
    session[:previous_url] = request.fullpath #url for user to come back after signing in
...

attendee_controller.rb : we create session[:attendee]

   def create
    if !current_user
     session[:attendee] = true
     redirect_to user_session_path
   else
...

app\controllers\users\sessions_controller.rb (user_session_path)

protected

  def after_sign_in_path_for(resource_or_scope)
    if session[:attendee]
      previous_url = session[:previous_url]
      session[:previous_url] = nil #clear session
      previous_url #going back to event page
    else
      super
    end
  end

More info into after_sign_in_path_for method here in the Devise How-To Wiki.

previous_url will bring us back to show view from the events.

Here is where the gem will come save the day :

app\controllers\events_controller.rb

before_action :attendee?, only: :show

private

    def attendee?
      if session[:attendee]
        session[:attendee] = nil
        repost(attendee_event_path, options: {authenticity_token: :auto})
      end
    end

This is the gem template :

repost('url' , params: {}, options: {})

Here is the gem link: https://github.com/vergilet/repost

Natblow
  • 53
  • 1
  • 8