预览摘要邮件错误:NoMethodError(nil:NilClass 未定义方法 `>=`)

你好,我在新版 Discourse 中预览摘要邮件时遇到以下错误:

NoMethodError (undefined method `>=' for nil:NilClass) /var/www/discourse/app/mailers/user_notifications.rb:227:in `digest'

堆栈跟踪

/var/www/discourse/app/mailers/user_notifications.rb:227:in `digest'
actionpack-6.0.1/lib/abstract_controller/base.rb:196:in `process_action'
actionpack-6.0.1/lib/abstract_controller/callbacks.rb:42:in `block in process_action'
activesupport-6.0.1/lib/active_support/callbacks.rb:101:in `run_callbacks'
actionpack-6.0.1/lib/abstract_controller/callbacks.rb:41:in `process_action'
actionpack-6.0.1/lib/abstract_controller/base.rb:136:in `process'
actionmailer-6.0.1/lib/action_mailer/rescuable.rb:25:in `block in process'
actionmailer-6.0.1/lib/action_mailer/rescuable.rb:17:in `handle_exceptions'
actionmailer-6.0.1/lib/action_mailer/rescuable.rb:24:in `process'
actionview-6.0.1/lib/action_view/rendering.rb:39:in `process'
actionmailer-6.0.1/lib/action_mailer/base.rb:637:in `block in process'
activesupport-6.0.1/lib/active_support/notifications.rb:180:in `block in instrument'
activesupport-6.0.1/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
activesupport-6.0.1/lib/active_support/notifications.rb:180:in `instrument'
actionmailer-6.0.1/lib/action_mailer/base.rb:636:in `process'
actionmailer-6.0.1/lib/action_mailer/message_delivery.rb:123:in `block in processed_mailer'
actionmailer-6.0.1/lib/action_mailer/message_delivery.rb:122:in `tap'
actionmailer-6.0.1/lib/action_mailer/message_delivery.rb:122:in `processed_mailer'
actionmailer-6.0.1/lib/action_mailer/message_delivery.rb:29:in `__getobj__'
/usr/local/lib/ruby/2.6.0/delegate.rb:80:in `method_missing'
/var/www/discourse/lib/email/renderer.rb:18:in `html'
/var/www/discourse/app/controllers/admin/email_controller.rb:93:in `preview_digest'
actionpack-6.0.1/lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
actionpack-6.0.1/lib/abstract_controller/base.rb:196:in `process_action'
actionpack-6.0.1/lib/action_controller/metal/rendering.rb:30:in `process_action'
actionpack-6.0.1/lib/abstract_controller/callbacks.rb:42:in `block in process_action'
activesupport-6.0.1/lib/active_support/callbacks.rb:135:in `run_callbacks'
actionpack-6.0.1/lib/abstract_controller/callbacks.rb:41:in `process_action'
actionpack-6.0.1/lib/action_controller/metal/rescue.rb:22:in `process_action'
actionpack-6.0.1/lib/action_controller/metal/instrumentation.rb:33:in `block in process_action'
activesupport-6.0.1/lib/active_support/notifications.rb:180:in `block in instrument'
activesupport-6.0.1/lib/active_support/notifications/instrumenter.rb:24:in `instrument'
activesupport-6.0.1/lib/active_support/notifications.rb:180:in `instrument'
actionpack-6.0.1/lib/action_controller/metal/instrumentation.rb:32:in `process_action'
actionpack-6.0.1/lib/action_controller/metal/params_wrapper.rb:245:in `process_action'
activerecord-6.0.1/lib/active_record/railties/controller_runtime.rb:27:in `process_action'
actionpack-6.0.1/lib/abstract_controller/base.rb:136:in `process'
actionview-6.0.1/lib/action_view/rendering.rb:39:in `process'
rack-mini-profiler-2.0.1/lib/mini_profiler/profiling_methods.rb:78:in `block in profile_method'
actionpack-6.0.1/lib/action_controller/metal.rb:191:in `dispatch'
actionpack-6.0.1/lib/action_controller/metal.rb:252:in `dispatch'
actionpack-6.0.1/lib/action_dispatch/routing/route_set.rb:51:in `dispatch'
actionpack-6.0.1/lib/action_dispatch/routing/route_set.rb:33:in `serve'
actionpack-6.0.1/lib/action_dispatch/routing/mapper.rb:18:in `block in <class:Constraints>'
actionpack-6.0.1/lib/action_dispatch/routing/mapper.rb:48:in `serve'
actionpack-6.0.1/lib/action_dispatch/journey/router.rb:49:in `block in serve'
actionpack-6.0.1/lib/action_dispatch/journey/router.rb:32:in `each'
actionpack-6.0.1/lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack-6.0.1/lib/action_dispatch/routing/route_set.rb:837:in `call'
/var/www/discourse/lib/middleware/omniauth_bypass_middleware.rb:68:in `call'
rack-2.0.8/lib/rack/tempfile_reaper.rb:15:in `call'
rack-2.0.8/lib/rack/conditional_get.rb:25:in `call'
rack-2.0.8/lib/rack/head.rb:12:in `call'
/var/www/discourse/lib/content_security_policy/middleware.rb:12:in `call'
/var/www/discourse/lib/middleware/anonymous_cache.rb:318:in `call'
rack-2.0.8/lib/rack/session/abstract/id.rb:259:in `context'
rack-2.0.8/lib/rack/session/abstract/id.rb:253:in `call'
actionpack-6.0.1/lib/action_dispatch/middleware/cookies.rb:648:in `call'
actionpack-6.0.1/lib/action_dispatch/middleware/callbacks.rb:27:in `block in call'
activesupport-6.0.1/lib/active_support/callbacks.rb:101:in `run_callbacks'
actionpack-6.0.1/lib/action_dispatch/middleware/callbacks.rb:26:in `call'
actionpack-6.0.1/lib/action_dispatch/middleware/actionable_exceptions.rb:17:in `call'
actionpack-6.0.1/lib/action_dispatch/middleware/debug_exceptions.rb:32:in `call'
actionpack-6.0.1/lib/action_dispatch/middleware/show_exceptions.rb:33:in `call'
logster-2.8.0/lib/logster/middleware/reporter.rb:43:in `call'
railties-6.0.1/lib/rails/rack/logger.rb:38:in `call_app'
railties-6.0.1/lib/rails/rack/logger.rb:28:in `call'
/var/www/discourse/config/initializers/100-quiet_logger.rb:18:in `call'
/var/www/discourse/config/initializers/100-silence_logger.rb:31:in `call'
actionpack-6.0.1/lib/action_dispatch/middleware/remote_ip.rb:81:in `call'
actionpack-6.0.1/lib/action_dispatch/middleware/request_id.rb:27:in `call'
/var/www/discourse/lib/middleware/enforce_hostname.rb:22:in `call'
rack-2.0.8/lib/rack/method_override.rb:22:in `call'
actionpack-6.0.1/lib/action_dispatch/middleware/executor.rb:14:in `call'
rack-2.0.8/lib/rack/sendfile.rb:111:in `call'
actionpack-6.0.1/lib/action_dispatch/middleware/host_authorization.rb:77:in `call'
rack-mini-profiler-2.0.1/lib/mini_profiler/profiler.rb:200:in `call'
message_bus-2.2.4/lib/message_bus/rack/middleware.rb:57:in `call'
/var/www/discourse/lib/middleware/request_tracker.rb:172:in `call'
railties-6.0.1/lib/rails/engine.rb:526:in `call'
railties-6.0.1/lib/rails/railtie.rb:190:in `public_send'
railties-6.0.1/lib/rails/railtie.rb:190:in `method_missing'
rack-2.0.8/lib/rack/urlmap.rb:68:in `block in call'
rack-2.0.8/lib/rack/urlmap.rb:53:in `each'
rack-2.0.8/lib/rack/urlmap.rb:53:in `call'
unicorn-5.5.4/lib/unicorn/http_server.rb:605:in `process_client'
unicorn-5.5.4/lib/unicorn/http_server.rb:700:in `worker_loop'
unicorn-5.5.4/lib/unicorn/http_server.rb:548:in `spawn_missing_workers'
unicorn-5.5.4/lib/unicorn/http_server.rb:144:in `start'
unicorn-5.5.4/bin/unicorn:128:in `<top (required)>'
/var/www/discourse/vendor/bundle/ruby/2.6.0/bin/unicorn:23:in `load'
/var/www/discourse/vendor/bundle/ruby/2.6.0/bin/unicorn:23:in `<main>'

如果用户设置了时间段,此问题可以解决:

偏好设置 > 邮件 > 活动摘要

我们能否复现这个问题 @tshenry

我尝试在我们的托管基础设施上通过新实例以及全新的 DO Droplet 触发此问题,但未能复现。

@zcuric,能否提供更多具体信息?如果能提供一个可稳定复现该错误的方法,那就太好了。

@tshenry
据我所知,步骤如下:

  1. 创建新实例
  2. 从开发实例导入设置(如下所示,其中移除了部分个人设置)到新实例
suggested_topics: '0'
post_menu: read|share|edit|bookmark|delete|flag|admin|reply
desktop_category_page_style: categories_only
fixed_category_positions: 'true'
fixed_category_positions_on_create: 'true'
enable_badges: 'false'
push_notifications_prompt: 'false'
login_required: 'true'
email_editable: 'false'
public_user_custom_fields: is_learning
enable_user_directory: 'false'
hide_user_profiles_from_public: 'true'
max_notifications_per_user: '10'
enable_group_directory: 'false'
title_prettify: 'false'
allow_uncategorized_topics: 'false'
enable_personal_messages: 'false'
enable_system_message_replies: 'false'
edit_history_visible_to_public: 'false'
max_reply_history: '4'
newuser_max_mentions_per_post: '10'
emoji_set: google
email_time_window_mins: '30'
email_accent_bg_color: F1F3F4
email_accent_fg_color: "#343F79"
email_link_color: "#343F79"
reply_by_email_enabled: 'true'
manual_polling_enabled: 'true'
pop3_polling_ssl: 'false'
pop3_polling_openssl_verify: 'false'
log_mail_processing_failures: 'true'
email_in: 'true'
email_in_min_trust: '0'
unsubscribe_via_email_footer: 'true'
theme_authorized_extensions: jpg|jpeg|png|woff|woff2|svg|eot|ttf|otf|gif|js|*
authorized_extensions: jpg|jpeg|png|gif|*
allow_uploaded_avatars: 'false'
restrict_letter_avatar_colors: 343F79
default_trust_level: '1'
allow_flagging_staff: 'false'
send_tl1_welcome_message: 'false'
trusted_users_can_edit_others: 'false'
detailed_404: 'true'
enable_flash_video_onebox: 'true'
auto_silence_fast_typers_on_first_post: 'false'
max_edits_per_day: '100'
max_topics_in_first_day: '10'
privacy_policy_url: "/t/about/6"
search_prefer_recent_posts: 'true'
new_version_emails: 'false'
educate_until_posts: '1'
disable_avatar_education_message: 'true'
show_create_topics_notice: 'false'
likes_notification_consolidation_window_mins: '1'
automatically_unpin_topics: 'false'
default_email_digest_frequency: '0'
default_email_mailing_list_mode: 'true'
default_other_like_notification_frequency: '3'
dashboard_general_tab_activity_metrics: page_view_total_reqs|visits|time_to_first_response|user_to_user_private_messages_with_replies
discourse_narrative_bot_enabled: 'false'
disable_discourse_narrative_bot_welcome_post: 'true'
discourse_narrative_bot_welcome_post_delay: '1'
allow_solved_on_all_topics: 'true
  1. 出现了此错误。

好吧,这确实有点棘手!我最终在一个全新、自行安装的环境中通过导入站点设置成功复现了问题(这似乎是关键所在)。目前我认为已经将其定位到某个特定设置。以下是导致该问题的完整复现步骤:

  1. 按照我们的 安装指南 操作,直到管理员创建步骤(先不要创建管理员)。进入应用:

    ./launcher enter app
    

    /var/www/discourse 目录下创建一个 settings.yml 文件,内容如下:

    ---
    default_email_digest_frequency: '0'
    
  2. 运行

    rake site_settings:import < settings.yml
    

    你应该会看到类似 Changed default_email_digest_frequency FROM: 10080 TO: 0 的提示。

  3. 通过 UI 创建管理员,跳过设置向导,直接进入站点设置中的摘要预览。

  4. 你会看到以下内容,并在 /logs 中看到相关条目:


以下是我从 Rails 控制台手动修复该情况的方法:

# 获取第一个也是唯一一个普通用户的用户选项
user_op = User.find(1).user_option

# 注意它被设置为 nil
user_op.digest_after_minutes
=> nil

# 将其设置为一个有效值。我选择了 0
user_op.digest_after_minutes = 0
user_op.save!

之后,摘要预览就能正常工作了。


我暂时还不确定修复方案是什么。以下代码让我有些怀疑,因为其中有一个大于 0 的测试,而我们的导入值是 0:

@codinghorror 你认为这是一个如此边缘的情况,以至于我们应该等待“三次法则”(rule of 3)出现更多类似案例吗?还是你希望我或其他人进一步调查并修复这个问题?

可能是个简单的修复?也许 @sam 可以安排在周一?