【问题标题】:rails controller action + rendering bugrails 控制器动作 + 渲染错误
【发布时间】:2016-11-16 12:39:45
【问题描述】:

我的应用中有通知系统。当用户转到其他用户的页面(用户/显示页面)时,通知计数会减少,因为他/她可以看到公共聊天窗口。因此,例如,如果 sby 给您发短信,那么您有 1 条通知。当您进入发件人的显示页面时,您的通知将减少到 0。

一切正常,但我想重构代码,因为它变得杂乱无章。

您可以在下面看到旧代码和新代码。旧代码工作正常,但新代码存在一个奇怪的问题。当我到达用户页面并在控制器显示操作或模板中打印出current_user.new_chat_notification 属性时(我将其显示在标题中,因此它在每个页面上都可用)它显示 1。与此同时,如果我打印出控制台中的数字显示为 0。因此由于某种原因,数据库中的数字减少了,但控制器操作和视图不及时知道它。如果我转到其他页面,那么数字会降为零。所以下一个控制器动作已经知道数字减少并显示为0。我真的不明白旧代码和新代码之间有什么区别会导致这样的事情。

schema.rb

create_table "users", force: :cascade do |t|
  t.integer  "new_chat_notification",  default: 0
end

用户控制器

def show
  @user = User.find(params[:id])
  #FOLLOWING 3 LINES ARE PART OF THE UPDATE
  @conversation = Conversation.create_or_find_conversation(current_user.id, @user.id)
  @tasks = Task.uncompleted.between(current_user.id, @user.id).order("created_at DESC").includes(:assigner, :executor).paginate(page: params[:page], per_page: 14)
  @messages = @conversation.messages.includes(:user).order(created_at: :desc).limit(50).reverse
  current_user.decreasing_chat_notification_number(@user)
  respond_to do |format|
    format.html
    format.js { render template: "tasks/between.js.erb" }
  end
end

用户.rb

#FOLLOWING 2 LINES ARE PART OF THE UPDATE
has_many :notifications, foreign_key: "recipient_id", dependent: :destroy
validates :new_chat_notification, numericality: { only_integer: true, greater_than_or_equal_to: 0 }

def decreasing_chat_notification_number(sender)
  notification = notifications.between_chat_recipient(sender).unchecked.first
  checking_and_decreasing_notification(notification) if notification.present?
end

def checking_and_decreasing_notification(notification)
  notification.check_notification
  if notification.notifiable_type == "Message"
    # decrease_new_chat_notifications --> OLD CODE THAT WORKING PROPERLY
    NotificationSender.new(notification).decrease_new_chat_notifications # --> NEW CODE NOT WORKING PROPERLY
    ....
  else
    ....
  end
end

def decrease_new_chat_notifications
  decrement!(:new_chat_notification) if new_chat_notification > 0
end

notification_sender.rb(用于新代码)

class NotificationSender
  attr_reader :notification, :recipient

  def initialize(notification)
    @notification = notification
    @recipient = notification.recipient
  end

  def decrease_new_chat_notifications
    recipient.decrement!(:new_chat_notification) if recipient.new_chat_notification > 0
  end
end

【问题讨论】:

    标签: ruby-on-rails model-view-controller model controller


    【解决方案1】:

    不同之处可能在于这一行:

    @recipient = notification.recipient
    

    可能会从数据库加载收件人,重置状态。从您的代码来看,在调用 decreasing_chat_notification_number 之前,User 模型中是否存在任何状态变化并不明显。

    更新

    如果这确实是问题的原因(目前只是一个不受支持的建议),您可以将引用的收件人与通知一起加载。这样,当您初始化 NotificationSender 时,它的状态就不会意外地从数据库中更新。

    不要使用notification = notifications.between_chat_recipient(sender).unchecked.first,试试这个:

    notification = notifications.
        between_chat_recipient(sender).
        unchecked.
        includes(:recipient).
        first
    

    根据您的关联,确切的查询可能会有所不同,但同样,我们的想法是将接收者加载到与通知相同的数据库调用中,从而消除潜在的竞争条件。

    【讨论】:

    • Nic,你说的“从你的代码中看不出来”是什么意思?我还应该展示其他东西吗?如果这就是您所说的问题,我应该在代码中进行哪些更改才能使其正常工作?
    • 抱歉,我没有提供建议。请参阅我的更新答案。 “不明显”意味着代码的其他一些部分可能会起作用,但不清楚它们是在控制器中还是模型中,或者两者兼而有之。请先尝试该建议,如果它不能解决问题,请将users#show 操作和User 模型的完整代码添加到您的问题中。
    • Nic,添加了相关部分。还有用于实时通知的 Pusher gem,但是如果我从 user.rb 中的 checking_and_decreasing_notification 方法中删除 Pusher 触发器部分(我有 ....),问题仍然存在。在 if else 语句的另一部分有 other_notifications,它的作用类似于聊天通知,只是 notifiable_type 不同。我也有同样的问题,只是试图解决这个问题。我尝试了您的解决方案,但没有奏效。这太奇怪了,因为我看不出旧代码和新代码之间的区别。
    • 好的,谢谢。我什至不知道我应该从哪里开始搜索:O
    猜你喜欢
    • 1970-01-01
    • 2011-08-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-15
    • 1970-01-01
    • 2014-11-26
    相关资源
    最近更新 更多