Jordan Lee
Jan 2026
3 tabs
class ApplicationController < ActionController::Base
helper_method :turbo_native_app?
private
def turbo_native_app?
request.user_agent.to_s.match?(/Turbo Native/)
end
def set_turbo_native_headers
return unless turbo_native_app?
# Tell the app which navigation style to use
response.headers["Turbo-Visit-Action"] = "advance"
# Custom headers for native features
response.headers["X-Navbar-Title"] = @page_title if @page_title
end
end
<!DOCTYPE html>
<html>
<head>
<title><%= content_for(:title) || 'MyApp' %></title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
<%= javascript_importmap_tags %>
<% if turbo_native_app? %>
<meta name="turbo-native-app" content="true">
<% end %>
</head>
<body>
<% unless turbo_native_app? %>
<%= render "shared/navbar" %>
<% end %>
<main class="<%= turbo_native_app? ? 'pt-0' : 'pt-16' %>">
<%= yield %>
</main>
<% unless turbo_native_app? %>
<%= render "shared/footer" %>
<% end %>
</body>
</html>
<% content_for :title, @post.title %>
<article class="post">
<h1><%= @post.title %></h1>
<%= simple_format @post.body %>
<% if turbo_native_app? %>
<!-- Native app: use bridge to share -->
<%= link_to "Share", "#",
class: "btn btn-primary",
data: {
bridge: "share",
bridge_title: @post.title,
bridge_url: post_url(@post)
} %>
<% else %>
<!-- Web: use Web Share API or fallback -->
<%= link_to "Share", "#",
class: "btn btn-primary",
data: {
controller: "share",
action: "click->share#trigger"
} %>
<% end %>
</article>
3 files · ruby, erb
Explain with highlit
Turbo Native allows building iOS and Android apps using Rails server-rendered HTML with native navigation chrome. The web views communicate with native code via a JavaScript bridge for features like push notifications, camera access, or native UI patterns. I mark certain paths as non-turbo using data-turbo='false' to open them in native browsers or external modals. The server detects Turbo Native requests via user agent and can customize responses—hiding web-only UI, adjusting layouts, or returning native-friendly data. This approach delivers the development speed of web apps with the polish of native apps. For apps with limited custom UI needs, it's a compelling alternative to React Native.
Related snips
ruby
class CommentsController < ApplicationController
before_action :set_post
def create
@comment = @post.comments.build(comment_params)
System test: asserting Turbo Stream responses
rails
hotwire
turbo
by codesnips
4 tabs
ruby
class Post < ApplicationRecord
belongs_to :author, class_name: 'User'
has_many :comments, dependent: :destroy
scope :published, -> { where.not(published_at: nil).where('published_at <= ?', Time.current) }
scope :draft, -> { where(published_at: nil) }
ActiveRecord scopes for reusable query logic
rails
activerecord
patterns
by Alex Kumar
1 tab
ruby
module Api
module V1
class UsersController < BaseController
def show
user = User.includes(:profile).find(params[:id])
ETags for conditional requests and caching
rails
caching
http-caching
by Alex Kumar
1 tab
ruby
class PostsController < ApplicationController
def index
@posts = Post.includes(:author)
.order(created_at: :desc)
.page(params[:page])
.per(10)
Turbo Frames: infinite scroll with lazy-loading frame
rails
turbo
hotwire
by codesnips
4 tabs
ruby
require "csv"
class PeopleCsvStream
include Enumerable
HEADERS = %w[id full_name email signed_up_at plan].freeze
Resilient CSV Export as a Streamed Response
rails
performance
streaming
by codesnips
3 tabs
erb
<form data-controller="query-sync" data-action="change->query-sync#apply">
<select name="status" class="rounded border p-2">
<option value="">Any</option>
<option value="open">Open</option>
<option value="closed">Closed</option>
</select>
Filter UI that syncs query params via Stimulus (no front-end router)
rails
hotwire
stimulus
by Henry Kim
2 tabs
Share this code
Here's the card — post it anywhere.