DEV Community

Cover image for Master Shopify Embedded Apps with Rails 8
Sulman Baig
Sulman Baig

Posted on • Originally published at sulmanweb.com

Master Shopify Embedded Apps with Rails 8

Motivation

After building several Shopify embedded apps, I've learned valuable lessons about what works (and what definitely doesn't) in the embedded app environment. Today, I'm sharing these insights to help you avoid common pitfalls and build better Shopify apps.

The Challenge

Building embedded apps for Shopify presents unique challenges - particularly around navigation, authentication, and user experience. One of the biggest pitfalls? Trying to use regular URL navigation in an embedded app context.

Project Setup

First, let's look at the proper configuration for a Shopify embedded app:

# config/initializers/shopify_app.rb
ShopifyApp.configure do |config|
  config.embedded_app = true
  config.new_embedded_auth_strategy = false
  config.scope = "read_customers,write_customers"
  config.api_version = "2024-10"

  # Webhook configuration
  config.webhooks = [
    { topic: "app/uninstalled", address: "webhooks/app_uninstalled" },
    { topic: "customers/create", address: "webhooks/customers_create" }
  ]
end
Enter fullscreen mode Exit fullscreen mode

Do's and Don'ts

✅ DO: Use App Bridge for Navigation

// app/javascript/shopify_app.js
var AppBridge = window['app-bridge'];
var createApp = AppBridge.default;
window.app = createApp({
  apiKey: data.apiKey,
  host: data.host,
});

var actions = AppBridge.actions;
var TitleBar = actions.TitleBar;
TitleBar.create(app, {
  title: data.page,
});
Enter fullscreen mode Exit fullscreen mode

❌ DON'T: Use Regular Rails Links

Avoid using regular Rails link_to helpers without proper App Bridge handling:

<%# Wrong way %>
<%= link_to "Settings", settings_path %>

<%# Right way %>
<%= link_to "Settings", settings_path(request.query_parameters) %>
Enter fullscreen mode Exit fullscreen mode

✅ DO: Handle Authentication Properly

class AuthenticatedController < ApplicationController
  include ShopifyApp::EnsureHasSession

  before_action :verify_embedded_app_request

  private

  def verify_embedded_app_request
    if ShopifyAPI::Context.embedded? && 
       (!params[:embedded].present? || params[:embedded] != "1")
      redirect_to(ShopifyAPI::Auth.embedded_app_url(params[:host]).to_s + 
                 request.path, 
                 allow_other_host: true)
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

✅ DO: Implement Proper Flash Messages

# app/helpers/application_helper.rb
module ApplicationHelper
  def flash_class(type)
    case type.to_sym
    when :success, :notice
      "bg-green-50"
    when :error, :alert
      "bg-red-50"
    else
      "bg-blue-50"
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

✅ DO: Use Proper Layout for Embedded Apps

<%# app/views/layouts/embedded_app.html.erb %>
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://unpkg.com/@shopify/app-bridge@3.7.9"></script>
    <%= csrf_meta_tags %>
    <%= javascript_importmap_tags %>
  </head>
  <body>
    <div id="app">
      <%= render 'shared/navbar' %>
      <%= yield %>
    </div>

    <% if flash[:notice].present? || flash[:error].present? %>
      <script>
        document.addEventListener('DOMContentLoaded', function() {
          var Toast = window['app-bridge'].actions.Toast;

          <% if flash[:notice].present? %>
            Toast.create(window.app, {
              message: "<%= j flash[:notice] %>",
              duration: 5000
            }).dispatch(Toast.Action.SHOW);
          <% end %>
        });
      </script>
    <% end %>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

❌ DON'T: Forget Query Parameters

When creating links or forms, always include the necessary query parameters:

# app/controllers/application_controller.rb
def maintain_query_parameters
  @query_parameters = request.query_parameters
end
Enter fullscreen mode Exit fullscreen mode

✅ DO: Implement Proper Navigation

<%# app/views/shared/_navbar.html.erb %>
<nav class="bg-white border-b border-gray-200 fixed w-full z-50">
  <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
    <div class="flex justify-between h-16">
      <div class="hidden md:flex md:items-center md:space-x-6">
        <%= link_to "Home", 
            root_path(params.except(:action, :controller).permit!.to_h), 
            class: "text-gray-600 hover:text-gray-900 px-3 py-2" %>
      </div>
    </div>
  </div>
</nav>
Enter fullscreen mode Exit fullscreen mode

Common Pitfalls to Avoid

  1. Direct URL Manipulation
# Wrong
redirect_to settings_path

# Right
redirect_to settings_path(request.query_parameters)
Enter fullscreen mode Exit fullscreen mode
  1. Missing CSRF Protection
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  skip_before_action :verify_authenticity_token, if: :valid_shopify_request?

  private

  def valid_shopify_request?
    return true if request.headers["HTTP_AUTHORIZATION"]&.start_with?("Bearer ")
    return true if params[:session].present?
    false
  end
end
Enter fullscreen mode Exit fullscreen mode
  1. Improper Session Handling
class Shop < ActiveRecord::Base
  include ShopifyApp::ShopSessionStorageWithScopes

  def api_version
    ShopifyApp.configuration.api_version
  end
end
Enter fullscreen mode Exit fullscreen mode

Best Practices for Success

  1. Use App Bridge for All Navigation
  2. Maintain Query Parameters
  3. Implement Proper Error Handling
  4. Use Appropriate Authentication Checks
  5. Follow Shopify's Design Guidelines

Learning Journey

Building embedded Shopify apps has taught me the importance of proper navigation handling and session management. The biggest lesson? Never assume standard web development practices will work in an embedded context.

Results and Impact

  • Smoother user experience
  • Fewer authentication issues
  • Better app stability
  • Reduced support tickets

Next Steps

  1. Enhanced Error Handling

    • Implement better error boundaries
    • Add detailed logging
  2. Performance Optimization

    • Optimize App Bridge usage
    • Implement proper caching
  3. User Experience Improvements

    • Add loading states
    • Enhance feedback mechanisms

Conclusion

Building embedded Shopify apps requires a different mindset from traditional web development. By following these best practices and avoiding common pitfalls, you can create robust, user-friendly applications that integrate seamlessly with the Shopify admin.

Have you encountered other challenges while building Shopify embedded apps? Share your experiences in the comments below!


Happy Coding!


Originally published at sulmanweb

Top comments (0)