Skip to content

Commit c4f0d40

Browse files
authored
Merge pull request #22 from nativeapptemplate/connection_identification
Add ActionCable connection identification
2 parents 7c65d61 + 8544a62 commit c4f0d40

4 files changed

Lines changed: 60 additions & 7 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
11
module ApplicationCable
22
class Channel < ActionCable::Channel::Base
3+
# All current channels are public (Turbo::StreamsChannel for display pages).
4+
# If an authenticated channel is added in the future, reject unauthorized
5+
# connections in that channel's #subscribed method:
6+
#
7+
# def subscribed
8+
# reject unless connection.current_shopkeeper
9+
# end
310
end
411
end
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,25 @@
11
module ApplicationCable
22
class Connection < ActionCable::Connection::Base
3+
identified_by :current_shopkeeper, :current_account
4+
5+
def connect
6+
self.current_shopkeeper = find_shopkeeper
7+
self.current_account = find_account
8+
end
9+
10+
private
11+
12+
def find_shopkeeper
13+
env["warden"]&.user(:shopkeeper)
14+
end
15+
16+
# Extract the account UUID from the WebSocket upgrade request path,
17+
# matching how AccountMiddleware sets the current account for HTTP
18+
# requests. Display page URLs (display/shops/...) don't include an
19+
# account UUID, so this returns nil for public connections.
20+
def find_account
21+
_, account_id, = request.path.split("/", 3)
22+
Account.find_by(id: account_id) if AccountMiddleware::UUID_MATCHER.match?(account_id)
23+
end
324
end
425
end

app/views/display/shops/show.html.erb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
<%# These streams are public by design — display pages are unauthenticated %>
12
<%= turbo_stream_from @shop, :tb_stream_full_reload_entire_page %>
23
<%= turbo_stream_from @shop, :tb_stream_update_item_tags %>
34

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,35 @@
11
require "test_helper"
22

33
class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
4-
# test "connects with cookies" do
5-
# cookies.signed[:user_id] = 42
6-
#
7-
# connect
8-
#
9-
# assert_equal connection.user_id, "42"
10-
# end
4+
test "anonymous connection succeeds with nil shopkeeper and account" do
5+
connect
6+
7+
assert_nil connection.current_shopkeeper
8+
assert_nil connection.current_account
9+
end
10+
11+
test "authenticated connection identifies shopkeeper and account" do
12+
shopkeeper = shopkeepers(:one)
13+
account = shopkeeper.create_default_account
14+
warden = Minitest::Mock.new
15+
warden.expect(:user, shopkeeper, [:shopkeeper])
16+
17+
connect "/#{account.id}/cable", env: {"warden" => warden}
18+
19+
assert_equal shopkeeper, connection.current_shopkeeper
20+
assert_equal account, connection.current_account
21+
warden.verify
22+
end
23+
24+
test "connection without account UUID in path has nil account" do
25+
shopkeeper = shopkeepers(:one)
26+
warden = Minitest::Mock.new
27+
warden.expect(:user, shopkeeper, [:shopkeeper])
28+
29+
connect "/cable", env: {"warden" => warden}
30+
31+
assert_equal shopkeeper, connection.current_shopkeeper
32+
assert_nil connection.current_account
33+
warden.verify
34+
end
1135
end

0 commit comments

Comments
 (0)