You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rails 6.0.0 TypeError求助:POST API调用时nil转字符串失败

Fixing the 500 Error & TypeError in Your Cross-App API Authentication

Let's break down what's causing this 500 error and the TypeError - no implicit conversion of nil into String, then fix it step by step:

Key Issues Identified

  • Mismatched Parameter Names: Your homework app sends data under the api_user key, but Devise (assuming you're using it for main app auth) expects parameters under your resource name (typically user for a User model). This confuses Warden's authentication logic.
  • Incorrect Request Format: jQuery's $.post defaults to sending application/x-www-form-urlencoded data, not JSON. Even with the .json URL suffix, Rails might parse the data incorrectly, leading to silent authentication failures.
  • Missing Devise Controller Setup: Your custom API Sessions controller doesn't define resource_name, so when you call sign_in(resource_name, resource), resource_name is nil—triggering the string conversion error.
  • Uncaught Authentication Exceptions: Warden's authenticate! throws a Warden::NotAuthenticated exception on failure, which your code doesn't rescue. This leads to an unhandled server error instead of a proper 401 response.

Step-by-Step Fixes

1. Update the Homework App's API Request

Fix parameter naming, send proper JSON, and correct DOM selectors (your original code targeted parent classes instead of the input fields):

var login = document.querySelector(".login")
login.addEventListener("click", function(){
  // Use the correct input selectors from your form
  var email = document.querySelector(".mail-input")
  var password = document.querySelector(".pw-input")
  
  // Match the main app's expected parameter key (use `user` instead of `api_user`)
  let loginData = { user: { email: email.value.trim(), password: password.value.trim() } }
  
  $.ajax({
    url: "http://localhost:4000/api/login.json",
    method: "POST",
    contentType: "application/json", // Explicitly set JSON content type
    data: JSON.stringify(loginData), // Convert object to valid JSON string
    success: function(response){
      console.log("Login successful:", response)
      window.location.replace("http://localhost:3000/")
    },
    error: function(xhr){
      console.error("Login failed:", xhr.responseJSON)
    }
  })
})

2. Fix the Main App's Sessions Controller

Update the controller to handle exceptions, define resource_name, and clean up control flow:

class Api::SessionsController < ApplicationController
  include Devise::Controllers::Helpers # Import Devise helper methods
  skip_before_action :verify_authenticity_token # Skip CSRF checks for API requests

  def create
    unless request.format == :json
      sign_out
      render status: 406, json: { message: "JSON requests only." }
      return
    end

    begin
      # Authenticate with Warden, catching failures to avoid 500 errors
      resource = warden.authenticate!(auth_options)
    rescue Warden::NotAuthenticated
      render status: 401, json: { response: "Access denied." }
      return
    end

    # Use explicitly defined resource_name to prevent nil errors
    sign_in(resource_name, resource)
    respond_with resource, location: after_sign_in_path_for(resource) do |format|
      format.json { render json: { success: true, jwt: current_token, response: "Authentication successful" } }
    end
  end

  private

  # Define your resource name (match your main app's user model, e.g., :user)
  def resource_name
    :user
  end

  # Configure Warden authentication scope
  def auth_options
    { scope: resource_name }
  end
end

3. Verify Routes & CORS Configuration

  • Routes: Ensure your main app's config/routes.rb has the correct API login route:
    namespace :api do
      post 'login', to: 'sessions#create'
    end
    
  • CORS: Since your apps run on different ports, enable cross-origin requests in the main app:
    1. Add the rack-cors gem to your Gemfile and run bundle install.
    2. Create/update config/initializers/cors.rb:
      Rails.application.config.middleware.insert_before 0, Rack::Cors do
        allow do
          origins 'http://localhost:3000' # Your homework app's URL
          resource '*',
            headers: :any,
            methods: [:get, :post, :put, :patch, :delete, :options, :head]
        end
      end
      

After applying these changes, test the login flow again—you should no longer see the 500 error, and authentication should work as expected.

内容的提问来源于stack exchange,提问作者diego

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:44:33