Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,21 @@ class User < ApplicationRecord
end
```

Then mount the engine in your routes:
Then mount the engine in your routes. You can use it at the root level or within a scope:

```ruby
Rails.application.routes.draw do
# Simple usage
passwordless_for :users

# With custom options
passwordless_for :admins, at: '/admin', as: :admin

# Nested within a scope
scope ":locale" do
passwordless_for :users, as: :locale_user
end

# other routes
end
```
Expand Down
31 changes: 23 additions & 8 deletions lib/passwordless/router_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ module RouterHelpers
# passwordless_for :users, at: 'session_stuff', as: :user_session_things
# # or with a custom controller ...
# passwordless_for :users, controller: 'my_custom_controller'
# # or with a scope block ...
# scope ":locale" do
# passwordless_for :users
# end
# @param resource [Symbol] the pluralized symbol of a Model (e.g - :users).
# @param at [String] Optional - provide custom path for the passwordless
# engine to get mounted at (using the above example your URLs end
Expand All @@ -21,21 +25,32 @@ module RouterHelpers
# @param controller [String] Optional - provide a custom controller for
# sessions to use (using the above example the controller called would be MyCustomController
# (Default: 'passwordless/sessions')
def passwordless_for(resource, at: :na, as: :na, controller: "passwordless/sessions")
# @yield [scope] Optional - yields the current scope to a block for nested routes
# @yieldparam scope [ActionDispatch::Routing::Mapper::Scope] the current route scope
def passwordless_for(resource, at: :na, as: :na, controller: "passwordless/sessions", &block)
at == :na && at = "/#{resource.to_s}"
as == :na && as = resource.to_s

as = as.to_s + "_" unless !as || as.to_s.end_with?("_")

pwless_resource = Passwordless.add_resource(resource, controller: controller)

scope(defaults: pwless_resource.defaults) do
get("#{at}/sign_in", to: "#{controller}#new", as: :"#{as}sign_in")
post("#{at}/sign_in", to: "#{controller}#create")
get("#{at}/sign_in/:id", to: "#{controller}#show", as: :"verify_#{as}sign_in")
get("#{at}/sign_in/:id/:token", to: "#{controller}#confirm", as: :"confirm_#{as}sign_in")
patch("#{at}/sign_in/:id", to: "#{controller}#update")
match("#{at}/sign_out", to: "#{controller}#destroy", via: %i[get delete], as: :"#{as}sign_out")
scope_block = proc do
scope(defaults: pwless_resource.defaults) do
get("#{at}/sign_in", to: "#{controller}#new", as: :"#{as}sign_in")
post("#{at}/sign_in", to: "#{controller}#create")
get("#{at}/sign_in/:id", to: "#{controller}#show", as: :"verify_#{as}sign_in")
get("#{at}/sign_in/:id/:token", to: "#{controller}#confirm", as: :"confirm_#{as}sign_in")
patch("#{at}/sign_in/:id", to: "#{controller}#update")
match("#{at}/sign_out", to: "#{controller}#destroy", via: %i[get delete], as: :"#{as}sign_out")
end
end

if block_given?
scope(defaults: pwless_resource.defaults, &block)
instance_exec(&scope_block)
else
instance_exec(&scope_block)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see how this solves the problem described?

This talks about running passwordless_for with a block, not inside a scope block?

If block is passed, it runs the block first, then runs passwordless_for exactly like it does now?

Maybe I'm reading it wrong?

end
end
end
Expand Down
57 changes: 57 additions & 0 deletions test/passwordless/router_helpers_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,63 @@ class RouterHelpersTest < ActionDispatch::IntegrationTest
assert_equal "/sign_in", url_helpers.auth_sign_in_path
end

test("nested within a scope") do
defaults = {authenticatable: "user", resource: "users", locale: "en"}

# Test GET /:locale/users/sign_in
assert_recognizes(
{controller: "passwordless/sessions", action: "new"}.merge(defaults),
{method: :get, path: "/locale/en/users/sign_in"},
defaults
)

# Test POST /:locale/users/sign_in
assert_recognizes(
{controller: "passwordless/sessions", action: "create"}.merge(defaults),
{method: :post, path: "/locale/en/users/sign_in", params: {passwordless: {email: "a@a"}}},
defaults
)

# Test GET /:locale/users/sign_in/:id
assert_recognizes(
{controller: "passwordless/sessions", action: "show", id: "123"}.merge(defaults),
{method: :get, path: "/locale/en/users/sign_in/123"},
defaults
)

# Test GET /:locale/users/sign_in/:id/:token
assert_recognizes(
{controller: "passwordless/sessions", action: "confirm", id: "123", token: "abc"}.merge(defaults),
{method: :get, path: "/locale/en/users/sign_in/123/abc"},
defaults
)

# Test PATCH /:locale/users/sign_in/:id
assert_recognizes(
{controller: "passwordless/sessions", action: "update", id: "123"}.merge(defaults),
{method: :patch, path: "/locale/en/users/sign_in/123"},
defaults
)

# Test DELETE /:locale/users/sign_out
assert_recognizes(
{controller: "passwordless/sessions", action: "destroy"}.merge(defaults),
{method: :delete, path: "/locale/en/users/sign_out"},
defaults
)

# Test GET /:locale/users/sign_out
assert_recognizes(
{controller: "passwordless/sessions", action: "destroy"}.merge(defaults),
{method: :get, path: "/locale/en/users/sign_out"},
defaults
)

# Test URL helpers
assert_equal "/locale/en/users/sign_in", url_helpers.locale_user_sign_in_path(locale: "en")
assert_equal "/locale/en/users/sign_out", url_helpers.locale_user_sign_out_path(locale: "en")
end

private

def url_helpers
Expand Down
Loading