pfaffman
(Jay Pfaffman)
2025 年 4 月 7 日午後 9:28
1
これは #バグ のようですが、何が起こっているのかわかりません。
多くのユーザーが /s/user/subscriptions/ を読み込もうとすると 500 エラーが発生します(/my/billing/subscriptions にアクセスしたとき)。
NoMethodError (undefined method `[]' for nil) app/controllers/application_controller.rb:427:in `block in with_resolved_locale' app/controllers/application_controller.rb:427:in `with_resolved_locale' l
NoMethodError (undefined method `[]' for nil)
app/controllers/application_controller.rb:427:in `block in with_resolved_locale'
app/controllers/application_controller.rb:427:in `with_resolved_locale'
lib/middleware/omniauth_bypass_middleware.rb:35:in `call'
lib/middleware/content_security_policy/middleware.rb:12:in `call'
lib/middleware/anonymous_cache.rb:410:in `call'
lib/middleware/csp_script_nonce_injector.rb:12:in `call'
config/initializers/008-rack-cors.rb:14:in `call'
lib/middleware/default_headers.rb:13:in `call'
config/initializers/100-quiet_logger.rb:20:in `call'
config/initializers/100-silence_logger.rb:29:in `call'
lib/middleware/enforce_hostname.rb:24:in `call'
lib/middleware/processing_request.rb:12:in `call'
lib/middleware/request_tracker.rb:385:in `call'
すべてのユーザーで壊れているわけではないので、偶然の一致であることを願っています。しかし、パターンが見つかりません。
以下は実行できます。
user=User.find_by_username 'xxx'
DiscourseSubscriptions::Customer.find_by(user_id: user.id)
そしてそれは機能します。
次にどこを見ればよいかわかりません。
「いいね!」 1
blake
(Blake Erickson)
2025 年 4 月 8 日午後 8:55
4
何か見落としているかもしれませんが、/s/<username>/subscriptions/ はプラグインのルートではありませんよね?
これまでのところ、ローカルサイトと本番サイトの両方で /my/billing/subscriptions にアクセスすると、/u/<username>/billing/subscriptions に正しくリダイレクトされ、500 エラーは発生していません。
これを再現するための他のヒントはありますか?
pfaffman
(Jay Pfaffman)
2025 年 4 月 8 日午後 9:13
5
ご協力ありがとうございます!
import EmberObject from "@ember/object";
import { ajax } from "discourse/lib/ajax";
import discourseComputed from "discourse/lib/decorators";
import { i18n } from "discourse-i18n";
import Plan from "discourse/plugins/discourse-subscriptions/discourse/models/plan";
export default class UserSubscription extends EmberObject {
static findAll() {
return ajax("/s/user/subscriptions", { method: "get" }).then((result) =>
result.map((subscription) => {
subscription.plan = Plan.create(subscription.plan);
return UserSubscription.create(subscription);
})
);
}
@discourseComputed("status")
canceled(status) {
return status === "canceled";
そのエンドポイントから取得しています。そして、このサーバーでは、一部のユーザーで 500 エラーが発生します(スクリーンショットを含めるべきだったと思います)。しばらく前から発生していたのではないでしょうか?彼らは私をアップグレードのために連れてきて、私はアップグレードしましたが、その後このエラーが報告されましたが、アップグレードで解決されることを期待していたようです(少なくともアップグレードで壊れたわけではありませんでした)。
blake:
これを再現するための他のヒントはありますか?
ゼロです。私の推測では、過去のある時点で何かが起こり、配列にアクセスする前に nil をテストしていない場所を見ましたが、配列から nil を取得するようになったということです。
「いいね!」 1
blake
(Blake Erickson)
2025 年 4 月 9 日午後 4:53
6
これはこのサイトだけの問題だと仮定してよいですか?他のサイトではこの問題は発生していませんか?はい、「バグ」があり、500を返すべきではないのですが、おそらくプランが見つからないなど、「不正な」データがどこかにあるのでしょう。Stripeで削除されたのに、プラグインのデータベースでは更新されなかったのかもしれません。
デバッグのために、これらのRailsコンソールコマンドを実行していただけますか?
Stripe.api_key = SiteSetting.discourse_subscriptions_secret_key
user = User.find_by(username: 'xxx')
customer = DiscourseSubscriptions::Customer.find_by(user_id: user.id)
subs = ::Stripe::Subscription.list(customer: stripe_customer_id, status: 'all')[:data]
subs.count # サブスクリプションの数を数える
subscription = subs.first # これを変更し、各サブスクリプションに対して以下の行を実行する
price_id = subscription[:items][:data].first[:price][:id]
plans = ::Stripe::Price.list(expand: ['data.product'], limit: 100)
plan = plans[:data].find { |p| p[:id] == price_id }
plan
プランまたはプランがnilを返すのではないかと考えていますが、これで問題の箇所を特定するのに役立ちます。サブスクリプションがいくつあり、プランが見つからないものがあるかどうか教えていただけますか?
おそらくコードの修正として、エラーが発生した場合はこれらのユーザーのサブスクリプションを返さないようにするでしょうが、実際にサブスクリプションがあるのに問題を解決しないのは良くありません。おそらく、「サブスクリプションが見つかりましたが、プランの詳細を読み込む際にエラーが発生しました。管理者に連絡してください」のようなエラーを返すようにするでしょう。
pfaffman
(Jay Pfaffman)
2025 年 4 月 9 日午後 6:34
7
クール。ありがとう!
サブスクリプションが1件ありました。
コードの修正点は1つです。
subs = ::Stripe::Subscription.list(customer: customer.stripe_customer_id, status: 'all')[:data]
プランは100件(おそらくそれ以上)あります。これが問題でしょうか?(limit: 1000 で試しましたが、何も変わりませんでした。これはStripe APIの制限でしょうか?)
もしプランが100件以上あると失敗するのでしょうか?ああ、そして失敗していないユーザーは、最初の100件のプランに含まれるプランを利用しています。
discourse(prod)> plan = plans[:data].find { |p| p[:id] == price_id }
discourse(prod)>
=> nil
編集:
はい。これを実行すると:
# 最後のアイテムのIDを取得
last_price_id = plans.data.last.id
# 次の100件を取得
next_plans = ::Stripe::Price.list(
expand: ['data.product'],
limit: 100,
starting_after: last_price_id
)
すると
discourse(prod)> next_plans[:data].find { |p| p[:id] == price_id }
探しているものが見つかります。
再度編集:next_plans.count == 8。10件のプランを削除するように提案しました。
「いいね!」 1
blake
(Blake Erickson)
2025 年 4 月 9 日午後 8:11
8
情報ありがとうございます。大変参考になります。
はい、それはコード修正なしで解決できますね。古いプランがたくさんある場合には良い方法だと思います。
また、ページネーションも追加します。これにより、再びこの問題が発生した場合でも、すべてを取得できるようになります。
「いいね!」 1
blake
(Blake Erickson)
クローズされました:
2025 年 4 月 14 日午後 2:00
10
このトピックは4日後に自動的に閉じられました。新しい返信は許可されていません。