2
votes

I have a Messenger chatbot in production using this rails gem. It sends an opt-in to allow people to subscribe. When they hit the subscribe button, the webhook sends a postback payload "SUB_YES_PAYLOAD" that allows us to save the subscriber and reply a confirmation message defined by our users (the message changes from a page using our bot to another).

However, sometimes the postback reply sends the confirmation message of ANOTHER page... I scratched my head during several hours but can't find what's the issue here?

Here is the webhook code:

Bot.on :postback do |postback|
  # We get the page record with the page ID sent by Facebook
  @core_bot = CoreBot.find_by_page_id(postback.recipient['id'])
  if postback.payload == 'SUB_YES_PAYLOAD'
    # We check the subscriber is not already subscribed in our db
    if BotUser.find_by_sender_id(postback.sender['id']).present? == false
      # save to the db
      url = "https://graph.facebook.com/v2.6/" + postback.sender['id'] + "?fields=first_name,last_name,profile_pic,locale,timezone,gender&access_token=" + @core_bot.page_access_token
      resp = Net::HTTP.get_response(URI.parse(url))
      @user_data = JSON.parse(resp.body)
      @first_name = @user_data['first_name']
      @last_name = @user_data['last_name']
      @profile_pic = @user_data['profile_pic']
      @locale = @user_data['locale']
      @timezone = @user_data['timezone']
      @gender = @user_data['gender']

      @bot_user = BotUser.new(core_bot_id: @core_bot.id, sender_id: postback.sender['id'], first_name: @first_name, last_name: @last_name, profile_pic: @profile_pic, locale: @locale, timezone: @timezone, gender: @gender)
      @bot_user.save
      if @bot_user.save
        # if the user defined a confirmation message in his settings
        if @core_bot.yes_subscribe_message.present? == true
          postback.reply({
              text: @core_bot.yes_subscribe_message # That's what's wrong here sometimes
          })
        else
          postback.reply({
              text: "Welcome!"
          })
        end
      end
    end
  end
end

Here is one picture of a wrong confirmation sent: wrong message

It seems like the @core_bot is not the right one when I call @core_bot.yes_subscribe_message but the subscriber is saved to the right @core_bot ID so there is no reason it changes just after...

My app is on a one Heroku standard web dyno and a Heroku Postgres Hobby classic database.

Edit, here is the CoreBot model:

#  id                    :integer          not null, primary key
#  user_id               :integer
#  page_name             :string
#  page_id               :integer
#  page_access_token     :string
#  greeting_message      :string
#  yes_subscribe_button  :string
#  no_subscribe_button   :string
#  yes_subscribe_message :string
#  no_subscribe_message  :string
#  created_at            :datetime         not null
#  updated_at            :datetime         not null
#  active                :boolean          default(TRUE)
#  picture               :string           default("https://scontent.xx.fbcdn.net/v/t1.0-1/p480x480/20729408_135562287047146_4447605348389117589_n.png?oh=ba7b4a319a002db384168f50e1ccfec5&oe=5AAE506E")
#

class CoreBot < ApplicationRecord
  validates_uniqueness_of :page_id
  validates :page_id, :presence => true
  has_secure_token

  belongs_to :user
  has_many :letters, dependent: :destroy
  has_many :bot_users, dependent: :destroy
  has_many :weekly_analytics, dependent: :destroy
  has_many :segments, dependent: :destroy
  has_many :sequences, dependent: :destroy
  has_many :invitations, dependent: :destroy
  has_one :checkbox_iframe, dependent: :destroy
  has_one :button_iframe, dependent: :destroy
end

Thanks.

1
Could you post the relevant contents of the CoreBot class? Since the right core_bot.id is saved, the error might be there? Is there maybe more logic to the yes_subscribe_message? Maybe it is overridden somewhere. - smallbutton
Also calling @bot_user.save once in the if is enough, btw. - smallbutton
You mean "if @bot_user.save" will actually save it as well as verify if it's actually successfully saved? I added the CoreBot model, if it's what you mean by the content of the CoreBot class. Thanks - nico_lrx
By the way, it seems those errors happen more frequently when there is more usage. Maybe it's related to my Heroku config? (I have thousands of users) - nico_lrx

1 Answers

2
votes

I think this happens because you use instance variables @core_bot and there is probably only one instance of your bot, that executes the block every time a user comes in. So if there is nothing happening in parallel, everything is fine, since the shared @core_botinstance is set and stays the same the whole time. But if you have a lot of users, a new @core_bot instance is added while the block is still running.

So the solution would be to just remove all @ signs, to make the variables be local in the scope of the execution of the block.

Bot.on :postback do |postback|
  # We get the page record with the page ID sent by Facebook
  core_bot = CoreBot.find_by_page_id(postback.recipient['id'])
  if postback.payload == 'SUB_YES_PAYLOAD'
    # We check the subscriber is not already subscribed in our db
    if BotUser.find_by_sender_id(postback.sender['id']).present? == false
      # save to the db
      url = "https://graph.facebook.com/v2.6/" + postback.sender['id'] + "?fields=first_name,last_name,profile_pic,locale,timezone,gender&access_token=" + core_bot.page_access_token
      resp = Net::HTTP.get_response(URI.parse(url))
      user_data = JSON.parse(resp.body)
      first_name = user_data['first_name']
      last_name = user_data['last_name']
      profile_pic = user_data['profile_pic']
      locale = user_data['locale']
      timezone = user_data['timezone']
      gender = user_data['gender']

      bot_user = BotUser.new(core_bot_id: core_bot.id, sender_id: postback.sender['id'], first_name: first_name, last_name: last_name, profile_pic: profile_pic, locale: locale, timezone: timezone, gender: gender)

      if bot_user.save
        # if the user defined a confirmation message in his settings
        if core_bot.yes_subscribe_message.present? == true
          postback.reply({
              text: core_bot.yes_subscribe_message 
          })
        else
          postback.reply({
              text: "Welcome!"
          })
        end
      end
    end
  end
end