NoMethodError in Devise::SessionsController#create

2019-08-16 09:42发布

问题:

I'm currently trying to write functionality for my quiz webapp that allows a user who reconnects to continue where they left off (possible reasons for reconnect are: because they lost their connection, or because they logged out unintentionally, or because they refreshed the page).

So I googled and found the solution, that I could write the method "after_sign_in_path_for(resource)" in the application_controller, and whatever I put in that method would be executed by Devise after a user logs in.


This solution works perfectly for when I try to render a static page (or even one of many static pages, depending on the "phase" parameter I save to my db). But my app has 2 kinds of users:

  • The "Teacher" who clicks links from static page to static page and
  • the "Student", who has no control, but gets pushed new HTML whenever the Teacher clicks (pushed = HTML is received over ActionCable and replaces the current page)

So now what happens when a student logs in is this:

  1. after_sign_in_path_for(resource) is called: determines the user is a Student and calls
  2. the find_current_page method in my quiz_session model: which checks the phase variable in my db and calls one of multiple methods on the serverside of my channel, e.g.
  3. resend_question_page class method in my IndividualUpdateChannel: this method builds the html and broadcasts it to the Student.

BUT: instead of receiving and displaying the sent HTML the Student gets "NoMethodError in Devise::SessionsController#create - undefined method `student_url' for #". In the logs it looks to me like 1., 2. and 3. are run, but then suddenly the app tries to redirect the Student somewhere? and fails.

Here is the console output: https://pastebin.com/FKmHF4qS

...
[ActionCable] Broadcasting to student_#3: {:phase=>1, :answers=>["<div class='student-layout'>The call returns immediately without </br>waiting for the I/O to complete.</div>", {"ids"=>[9, 10, 11, 12], "current_question_index"=>1}]}
Redirected to
Completed 500 Internal Server Error in 442ms (ActiveRecord: 103.6ms)

This is the full error message: And this is the rest of the trace: https://pastebin.com/psdyR2w2

And here is the code where the execution stops:

#app\channels\individual_update_channel.rb:
class IndividualUpdateChannel < ApplicationCable::Channel
  ...
  def self.resend_question_page(student)
    quiz_session = student.quiz_session
    new_answer_html = AnswerButtonCreation.new(quiz_session).create

    #This is where it stops
    ActionCable.server.broadcast("student_##{student.id}", phase: 1, answers: new_answer_html)
  end

I'm using Rails 5.0.2 and Ruby 2.3.3 with Devise 4.2.1 . This is my first Rails project, so please excuse if I got some best practices wrong. My googling of the inner workings of Devise didn't get me anywhere so I'd appreciate any help!


EDIT: This is my routes file:

Rails.application.routes.draw do

  resources :given_answers
  get 'students/set_quiz_session'

  resources :given_answers

  #change the sign_in and sign_out routes to /login and /logout
  devise_for :users, path: '', path_names: { sign_in: 'login',
                                             sign_out: 'logout'},
             :controllers => {:registrations => 'registrations'}

  resources :quiz_sessions, :answers, :questions, :quizzes, :courses

  # Setup static pages
  get 'teacher/quiz_start', to: 'pages#create_session', :as => :teacher_start_quiz
  get 'teacher/quiz_question', to: 'pages#show_question', :as => :teacher_question
  get 'teacher/quiz_question_result', to: 'pages#show_question_result', :as => :teacher_question_result
  get 'teacher/quiz_result', to: 'pages#show_quiz_result', :as => :teacher_quiz_result
  get 'teacher/home', to: 'pages#show', :role => "teacher", :page => "home", :as => :teacher_home

  get 'student/quiz_start', to: 'pages#join_session', :as => :student_start_quiz
  get 'student/home', :role => "student", :page => "home", :as => :student_home

  get ':role/:page', to: 'pages#show'
  root to: redirect('teacher/home'), :role => "teacher", :page => "home"

  mount ActionCable.server => '/cable'
end