ActionView::Template::Error (undefined method `tr' for nil:NilClass

1.4k views Asked by At

I am testing out the service-worker rails gem and am using VAPID private and public keys to send push notifications. I've succesfully been able to create push notifications locally, but when I deploy to heroku, the app raises the error stated above when trying to go to the push notification page. Here is the error:

      75] Started GET "/push-simple/" for 69.253.120.203 at 2017-02-12 06:37:35 +0000
2017-02-12T06:37:35.339318+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75] ActionView::Template::Error (undefined method `tr' for nil:NilClass
2017-02-12T06:37:35.333379+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75]   Rendering pages/push-simple.html.erb within layouts/application
2017-02-12T06:37:35.332337+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75] Processing by PagesController#show as HTML
2017-02-12T06:37:35.336377+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75]   Rendered pages/push-simple.html.erb within layouts/application (2.8ms)
2017-02-12T06:37:35.336998+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75] Completed 500 Internal Server Error in 4ms
2017-02-12T06:37:35.339281+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75]   
2017-02-12T06:37:35.339490+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75]     13: <script type="text/javascript">
2017-02-12T06:37:35.339320+00:00 app[web.1]: Did you mean?  try):
2017-02-12T06:37:35.339489+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75]     11: </div>
2017-02-12T06:37:35.339489+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75]     12: 
2017-02-12T06:37:35.339561+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75] app/views/pages/push-simple.html.erb:14:in `_app_views_pages_push_simple_html_erb__2838769268823495646_39526220'
2017-02-12T06:37:35.339491+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75]     15: </script>
2017-02-12T06:37:35.339491+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75]     14:   var publicKey = new Uint8Array(<%= WebpushClient.public_key_bytes %>);
2017-02-12T06:37:35.339492+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75]     16: <%= javascript_include_tag 'push-simple' %>
2017-02-12T06:37:35.339520+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75]   
2017-02-12T06:37:35.339560+00:00 app[web.1]: [3d626b62-4c1b-41ca-aad3-fc653dc96b75] app/clients/webpush_client.rb:7:in `public_key_bytes'

And here is my webpushclient where the VAPID keys are defined:

  class WebpushClient
    def self.public_key
      ENV['VAPID_PUBLIC_KEY']
    end

    def self.public_key_bytes
      Base64.urlsafe_decode64(public_key).bytes
    end

    def self.private_key
      ENV['VAPID_PRIVATE_KEY']
    end

    # Send webpush message using subscription parameters
    #
    # @param message [String] text to encrypt
    # @param subscription_params [Hash<Symbol, String>]
    # @option subscription_params [String] :endpoint url to send encrypted message
    # @option subscription_params [Hash<Symbol, String>] :keys auth keys to send with message for decryption
    # @return true/false
    def send_notification(message, endpoint: "", p256dh: "", auth: "")
      raise ArgumentError, ":endpoint param is required" if endpoint.blank?
      raise ArgumentError, "subscription :keys are missing" if p256dh.blank? || auth.blank?

      Rails.logger.info("Sending WebPush notification...............")
      Rails.logger.info("message: #{message}")
      Rails.logger.info("endpoint: #{endpoint}")
      Rails.logger.info("p256dh: #{p256dh}")
      Rails.logger.info("auth: #{auth}")

      Webpush.payload_send \
        message: message,
        endpoint: endpoint,
        p256dh: p256dh,
        auth: auth,
        vapid: {
          subject: "[email protected]",
          public_key: public_key,
          private_key: private_key
        }
    end

    def public_key
      self.class.public_key
    end

    def private_key
      self.class.private_key
    end
  end

and here is the script im using to call the public key:

<script type="text/javascript">
  var publicKey = new Uint8Array(<%= WebpushClient.public_key_bytes %>);
</script>
<%= javascript_include_tag 'push-react' %>

Like I said before, it works locally. I think I may have forgotten to define a variable, I've looked at similar posts and have been debugging for quite some time, but have had no luck. Any suggestions? I also want to add, I'm quite new, so if it's an obvious error, I'll completely understand.

1

There are 1 answers

2
Tom Lord On BEST ANSWER

Your error is coming from this method:

def self.public_key_bytes
  Base64.urlsafe_decode64(public_key).bytes
end

Looking up the source code for Base64#urlsafe_decode64, this is defined by:

def urlsafe_decode64(str)
  strict_decode64(str.tr("-_", "+/"))
end

This is where your undefined method 'tr' for nil:NilClass must be coming from: the public_key. Which you have defined by:

def self.public_key
  ENV['VAPID_PUBLIC_KEY']
end

...In other words, you have not set the environmental variable on your production server. That's why it works locally, but not on production.