Last month I changed jobs and returned to Rails development after a long time.

With a 6-year gap and only one month available for learning, I needed to efficiently grasp Rails 8’s new features and refresh my memory of existing ones.

So I decided to learn by building a working app together with Claude Code while referencing the Rails Guides. I temporarily subscribed to Claude Code’s Max plan at USD 100/mo.

Here’s the repository I created:

Learning Process

I used the Rails Guides as my main reference material.

1. Reviewing the Basics with Rails Guides

Following Getting Started with Rails , I created /products. I mainly learned about Active Storage (image uploads) and Action Text (rich text).

2. Learning Hotwire and Solid Trifecta

To learn Hotwire and Solid Trifecta, I created /chat and /posts.

  • /chat: Learned Action Cable, Solid Cable, and Stimulus
  • /posts: Learned Turbo Streams/Frames, Active Job, and Solid Queue. Added comment, follow, and notification features to a typical blog functionality

I learned through AI pair programming with Claude Code. The specific workflow was as follows:

  1. Create a GitHub Issue (e.g., #14 Follow Feature )
  2. Have Claude Code create a plan document (e.g., docs/plan-for-issue-14.md )
  3. Have it create a PR based on the plan while understanding the implementation (e.g., #38 )

I also utilized AI reviews from CodeRabbit. It pointed out N+1 queries and suggested adding tests, allowing me to maintain quality even in solo development. It’s great that it’s free for OSS.

Rails Features I Learned

Hotwire

Hotwire is a framework introduced in Rails 7 for achieving SPA-like UX. Hotwire consists of Turbo and Stimulus.

Turbo is further composed of three parts:

  • Turbo Drive: Speeds up page transitions (fetches and replaces HTML on link clicks)
  • Turbo Frames: Updates parts of a page (inline editing of comments, etc.)
  • Turbo Streams: Updates multiple locations simultaneously (updates list and count when adding comments)

Stimulus is a JavaScript framework, but it’s a very thin layer for adding minimal JS with HTML as the starting point. I used it for UI control in the chat feature.

I utilized Turbo Streams in the comment feature. When a comment is posted, model callbacks broadcast it to other users’ browsers in real-time.

# app/models/comment.rb
class Comment < ApplicationRecord
  belongs_to :post, counter_cache: true
  belongs_to :user

  after_create_commit do
    # Append to comment list
    broadcast_append_to post,
                        target: "comments",
                        partial: "comments/comment",
                        locals: { comment: self, allow_actions: false }
    # Update comment count
    broadcast_replace_to post,
                         target: "comment_count_#{post.id}",
                         partial: "posts/comment_count",
                         locals: { post: post }
  end
end

Solid Trifecta

“Solid Trifecta” introduced in Rails 8 eliminates the need for external middleware like Redis or Memcached.

  • Solid Queue: Database-based Active Job backend
  • Solid Cable: Database-based Action Cable adapter
  • Solid Cache: Database-based cache store (not used this time)

I used Active Job + Solid Queue for the scheduled post feature. When you set a future datetime for published_at, a job executes at that time to publish the article.

# app/jobs/publish_post_job.rb
class PublishPostJob < ApplicationJob
  queue_as :default

  def perform(post_id, scheduled_at)
    post = Post.find_by(id: post_id)
    return unless post

    # Idempotency: Skip if already published
    return if post.published

    # Skip if publish datetime was changed
    return if post.published_at.blank? || post.published_at.to_i != scheduled_at

    post.update!(published: true)
  end
end

You can check job execution status with Mission Control Jobs. Access http://localhost:3000/jobs in development to view job history and queue status in a Web UI.

Other Features

  • Eager Loading: includes/preload/eager_load to prevent N+1 queries
  • has_secure_password + rate_limit: User authentication and rate limiting
  • Counter Cache: Efficient retrieval of comment counts (belongs_to :post, counter_cache: true)
  • Foreign key constraint on_delete: :cascade: Automatically deletes child records when parent is deleted. Used alongside Rails’ dependent: :destroy to maintain DB-level integrity
  • Shallow Routing: Specifying shallow: true for nested resources shortens URLs for member actions (show/edit/update/destroy)
  • Polymorphic Association: Used for notification feature. Manages follow and comment notifications uniformly
  • Self-Referential Association: Used for follow feature. Expresses many-to-many relationships with a single follows table

Conclusion

Despite a 6-year gap, I was able to learn efficiently with Rails Guides and Claude Code.

My mental model was stuck around the time of “temporarily disabling Turbolinks…”, so I was quite impressed by Hotwire’s ability to achieve SPA-like UX with almost no JavaScript. My memory of Rails was that it often served as an API server or adopted React for the frontend, but I now think Hotwire should be considered first.

Solid Queue and Solid Cable are also nice because you can start with just RDS, reducing the number of components.

Note that I didn’t write many tests this time. The goal was to learn Rails features, so I’ll save test re-learning for another time.

I’ll continue working through the open Issues while continuing to learn.

By the way, after mastering the basics with the Rails Guides, I reinforced my learning with a Zenn book about Rails 8 and Hotwire1. The practical content helped me gain a more concrete understanding of development with Hotwire.

References