ActionCable のセットアップ、チャネルのリッスン、リクエストの認証などを正常に行うことができました。ただし、作成直後にチャネルに接続しようとすると、奇妙なバグが発生します (説明が難しい、以下を参照)。
セットアップがあり、プロファイルには壁があり、壁には多くの投稿が含まれています。各投稿には独自のチャンネルがあり、ウォール自体にも独自のチャンネルがあります。壁に投稿が作成されると、ActionCable を介して更新されます。
# Wall's Cable Channel
class WallsChannel < ApplicationCable::Channel
def subscribed
profile = Profile.find_by_id params[:id]
if ability.can? :subscribe, profile
stream_from "Wall(#{profile.id})"
else
reject
end
end
end
# Broadcasting to the wall
ActionCable.server.broadcast 'Wall(:id:)', { :data: }
# Client Side
GlobalCable.cable.subscriptions.create({channel: 'WallsChannel', id :id: }, {
received: function(data) {
// do stuff with a new post on a wall
}
});
単純化しましたが、これは意図したとおりに機能します。新しい投稿が作成されると、ウォール チャネルがトリガーされ、クライアントは投稿を受け取り、すべてが有効になります。
問題は、ブロードキャストされた新しい投稿を接続することです。新しい投稿を聞きに行くと、データベースから投稿を取得できません:
# Posts Cable Channel
class PostsChannel < ApplicationCable::Channel
def subscribed
post = Post.find_by_id params[:id]
if ability.can? :subscribe, post
stream_from "Post({#{post.id}})"
else
reject
end
end
end
# Client side
GlobalCable.cable.subscriptions.create({ channel: 'PostsChannel', id: id }, {
received: function(data) {
// do stuff
}
});
具体的には、サブスクライブした PostsChannel が適切な ID で呼び出されますが、投稿を取得しようとすると、次のようになります。
post = Post.find_by_id params[:id]
# SQL that is generated
# SELECT `posts`.* FROM `posts` WHERE `posts`.`id` = :id: LIMIT 1
# ^ Always returns null even though we just created the post
何が起こっても常に null を返します。つまり、100% 存在しているにもかかわらず、DB から Post をフェッチできません。
壁にすでにいくつかの投稿がある場合、それらは正常に接続できます。投稿が作成され、ActionCable を介してブロードキャストされた場合にのみ、DB で見つけることができません。ページをリロードすると、作成したばかりの投稿が機能します。新しくブロードキャストされた投稿がデータベースで見つからない理由がわからない