Reputation: 2380
I have notification system in my app. When the user goes to other user's page (users/show page), the notification count gets decreased since he/she can see the common chat window. So for instance if sby texted you then you have 1 notification. When you get on the sender's show page your notifications gets decreased to 0.
Everything worked fine, but I wanted to refactor the code since it was getting cluttered.
Below you can see the old and the new code. The old code works fine but there is a weird problem with the new code. When I get to the user page and I print out the current_user.new_chat_notification
attribute in the controller show action or in the template (I show it in the header so it's available on every page) it shows 1. In the meantime if I print out the number in the console it shows 0. So for some reason the number gets decreased in the db, but the controller action and the view don't know about it in time. If I go to an other page then the number goes down to zero. So the next controller action already knows that the number was decreased and shows 0. I don't really understand what's the difference between the old and new code that can causes something like this.
schema.rb
create_table "users", force: :cascade do |t|
t.integer "new_chat_notification", default: 0
end
users controller
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
user.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 (for new code)
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
Upvotes: 0
Views: 35
Reputation: 5156
The difference may be in the fact that this line:
@recipient = notification.recipient
may load the recipient from the database, resetting the state. It's not obvious from your code whether there is any state change in the User
model before the decreasing_chat_notification_number
gets called.
UPDATE
If this is in fact the reason for the issue (which is currently just an unsupported suggestion), you could load your referenced recipient along with the notification. This way the it's state will not unexpectedly be updated from the database when you're initializing the NotificationSender
.
Instead of notification = notifications.between_chat_recipient(sender).unchecked.first
, try this:
notification = notifications.
between_chat_recipient(sender).
unchecked.
includes(:recipient).
first
The exact query may be different depending on your associations, but again, the idea is to load the recipient in the same database call as the notification, thus removing the potential race condition.
Upvotes: 1