Master Shopify Embedded Apps with Rails 8

Senior Software Engineer with 12 years of expertise in Ruby on Rails and Vue.js, specializing in health, e-commerce, staffing, and transport. Experienced in software development and version analysis.
Search for a command to run...

Senior Software Engineer with 12 years of expertise in Ruby on Rails and Vue.js, specializing in health, e-commerce, staffing, and transport. Experienced in software development and version analysis.
No comments yet. Be the first to comment.
As a developer working with Shopify's ecosystem, I recently built a multi-tenant SaaS application that synchronizes customer data between Shopify stores and external services. In this article, I'll share my experience and technical insights into crea...

As developers, we're always looking for ways to streamline our deployment process while maintaining security and reliability. Today, I'm excited to share my experience setting up an automated deployment pipeline for a Rails application using Dokku an...

The Challenge: Modernizing Rails Deployment When I recently needed to deploy my Rails 8 application with multiple databases, I faced a common dilemma: choosing between expensive managed solutions and complex self-managed servers. My requirements were...

The Cost-Benefit Realization As a Rails developer who recently migrated from Heroku to Dokku, I want to share my journey and the surprising benefits I discovered. This transition wasn't just about cost savings—it opened up new possibilities for my de...

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.
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.
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
// 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,
});
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) %>
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
# 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
<%# 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>
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
<%# 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>
redirect_to settings_path(request.query_parameters)
2. **Missing CSRF Protection**
```ruby
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
Improper Session Handling
class Shop < ActiveRecord::Base
include ShopifyApp::ShopSessionStorageWithScopes
def api_version
ShopifyApp.configuration.api_version
end
end
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.
Enhanced Error Handling
Performance Optimization
User Experience Improvements
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!