如何协调 Devise reset-password 路由与 ApiConstraints?

How to conciliate Devise reset-password route with ApiConstraints?

我正在使用 devise_token_auth 并且一切正常,直到我向路由添加 API 约束:constraints: ApiConstraint.new(version: 4, default: true)

Rails.application.routes.draw do
  namespace :api do
    scope module: :v4, constraints: ApiConstraint.new(version: 4, default: true) do
      # Token auth routes available at /api/auth
      mount_devise_token_auth_for "User", at: "auth"
    end
  end
end

添加这些约束会限制对路由的访问,除非请求包含正确的 headers:

class ApiConstraint
  attr_reader :version

  VENDOR_MIME = "application/vnd.myproject-v%d"

  def initialize(version: "4", default: false)
    @version, @default = version, default
  end

  def matches?(request)
    byebug # <-- I wish there was something like request.current_path available
    return @default unless request.headers.key?("accept")
    request
      .headers
      .fetch("accept")
      .include?(VENDOR_MIME % version)
  end
end

我意识到这对于我们通过电子邮件收到的重置密码link是有问题的:

https://myproject.herokuapp.com/api/auth/password/edit?reset_password_token=...

...因为它不能携带任何 headers!

我可以将用户重定向到一个网页,该网页然后使用适当的 headers 进行 AJAX 调用,但我想知道是否有办法增强我的 routes.rbApiConstraint class 要在 /auth/password/edit 路线上例外?

您可以使用 request.urlrequest.fullpathrequest.params 访问您需要的数据。

更重要的是,为了弄清楚在运行时哪些方法对您可用,一旦 REPL 在您放置 byebug 调试器条目的行上打开,您可以使用以下这些方法(假设你使用 pry):

ls # display everything in the current scope
cd request # or any other variable or instance variable.
cd .. # you can navigate your code as if it was a filesystem

request.methods.grep /path/
request.methods.grep /url/
request.methods.grep /param/

# or

cd request
methods.grep /query/

OP更新

# api_constraint.rb
def initialize(version: "4", default: false, exceptions: [])
  @version, @default, @exceptions = version, default, exceptions
end

def matches?(request)
  return true if @exceptions.include? request.path
  ...
end
#routes.rb
scope module: :v4, constraints: ApiConstraint.new(version: 4, default: true, exceptions: [
  "/api/auth/password/edit"
]) do
  ...
end