Tired of bloated models that won't stop growing?
Development slowed to a crawl due to ever-increasing complexity?
Bogged down by an ever-growing list of gems you think will solve your problems?
Determined that next time, you'll “do it right”?
This book can help.
Practical tips for each part of Rails…with examples
Learn to use Rails…not abstract it away
Manage & isolate your business logic…without fancy patterns or libraries
Messy models with entangled dependencies and confusing callbacks? Instead, put business logic in plain Ruby classes that use your models to access the database.
Trying to fit functionality into resources based on your database tables? Try using custom resources with standard routes and Active Models instead of tons of custom routes.
Fighting with JavaScript, APIs, and Source Maps? Embrace server-rendered views.
Slow test suite? Don't over test. Controllers don't need a test if you have a system test. Simple validations don't need tests. If your jobs are a single-line delegation to business logic, why test them?
Buy Now and learn more of these tips. The book has extended examples and detailed, pragmatic explanations for when to use—or not use—each technique, all based on real-world experience.
What You Get
Over 450 Pages of practical tips on building Rails apps.
A beautifully typeset, DRM-free PDF for reading on any device, replete with an index for quick reference.
Three e-book ready PDFs in three font sizes for great typesetting you can read.
DRM-free ePub that works with iBooks, Kobo, Kindle and more!
A plain text Markdown version for all the grepping your heart desires.
Prefer it Print?
Why no package on print and electronic? Due to the realities of self-publishing, I can't offer you a package deal on both the ebook and the print version. My recommendation is to buy the version that you find most comfortable for reading.
Versions
This book's guidance applies to generally any Rails or Ruby version, however the book is kept up to date with the latest versions.
See the CHANGELOG to understand the differences in each release of the book.
Technology | Version |
---|---|
Rails | 7.1 |
Ruby | 3.2 |
This book's guidance applies to generally any Rails or Ruby version, however the book is kept up to date with the latest versions.
- Rails
- 7.1
- Ruby
- 3.2
See the CHANGELOG to understand the differences in each release of the book.
International Pricing
I realize the cost of living outside the United States can be wildly different from living in the U.S. and that a $50 book can be a big investment. I have created several discount codes that will bring the price down to a level that's more in line with the purchasing power in your country.
It's not perfect, and you are on your honor to choose the best discount for where you live. Visit my website for more info and then use the best code at checkout for the eBook. If you are buying the print book from Amazon, I have adjusted the pricing in Amazon already, though Amazon only allows me to set pricing for certain countries.
About Me
My name is David Bryant Copeland and I've spent the last ten years working on long-lived Rails apps. I've worked on a huge monolith whose construction was not managed as well as greenfield apps that evolved over many years from monoliths to a microservices architecture.
13 years prior to that I worked on various technologies and apps both for consulting clients and startups. Lastly, I've advised several startups using Rails and seen first-hand how small mistakes made early on can have a cascading effect on team sustainabilty.
The content of this book is based on my actual experience—I've really done everything in the book. I've seen (and made) decisions that both lead to great sustianbility as well as harmed it. There's nothing theoretical about what's in the book.
Feel free to look at my resume to see what my experience is. I've also authored several technical books, including Agile Web Development with Rails 6, The Senior Software Engineer, Ruby on Rails Background Jobs with Sidekiq, and SOLID is not Solid.
I go by “Dave” and am @davetron5000 on Mastodon. I love to talk Rails, cocktails, cats, and scuba.
Table of Contents
- Introduction
- Why This Book Exists
- What is Sustainability?
- Why Care About Sustainability?
- How to Value Sustainability
- Assumptions
- Opportunity and Carrying Costs
- Why should you trust me?
- The Rails Application Architecture
- Boundaries
- Views
- Models
- Everything Else
- The Pros and Cons of the Rails Application Architecture
- Where We Go From Here
- Following Along in This Book
- Typographic Conventions
- Software Versions
- Sample Code
- Start Your App Off Right
- Creating a Rails App
- Using The Environment for Runtime Configuration
- Configuring Local Development Environment with dotenv
- Automating Application Setup with bin/setup
- Running the Application Locally with bin/run
- Putting Tests and Other Quality Checks in bin/ci
- Improving Production Logging with lograge
- Business Logic (Does Not Go in Active Records)
- Business Logic Makes Your App Special…and Complex
- Bugs in Commonly-Used Classes Have Wide Effects
- Business Logic in Active Records Puts Churn and Complexity in Critical Classes
- Example Design of a Feature
- Why This Book Exists
- Deep Dive into Rails
- Routes and URLs
- Always Use Canonical Routes that Conform to Rails’ Defaults
- Never Configure Routes That Aren’t Being Used
- Vanity URLs Should Redirect to a Canonical Route
- Don’t Create Custom Actions, Create More Resources
- Use Nested Routes Strategically
- Nested Routes Can Organize Content Pages
- HTML Templates
- Use Semantic HTML
- Ideally, Expose One Instance Variable Per Action
- Think of Partials as Re-usable Components
- Just Use ERB
- Helpers
- Don’t Conflate Helpers with Your Domain
- Helpers are Best at Exposing Global UI State and Generating Markup
- Define Helpers in As Few Locations as Possible
- Presenters, Decorators, and View Models Have Their Own Problems
- Use Rails’ APIs to Generate Markup
- Helpers Should Be Tested and Thus Testable
- CSS
- Adopt a Design System
- Adopt a CSS Strategy
- Create a Living Style Guide to Document Your Design System and CSS Strategy
- Minimize JavaScript
- How and Why JavaScript is a Serious Liability
- Embrace Server-Rendered Rails Views
- Tweak Turbo to Provide a Slightly Better Experience
- Carefully Manage the JavaScript You Need
- Embrace Plain JavaScript for Basic Interactions
- Carefully Choose One Framework When You Need It
- Ensure System Tests Fail When JavaScript is Broken
- Testing the View
- Understand the Value and Cost of Tests
- Use :rack_test for non-JavaScript User Flows
- Test Against Default Markup and Content Initially
- Cultivate Explicit Diagnostic Tools to Debug Test Failures
- Fake The Back-end To Get System Tests Passing
- Use data-testid Attributes to Combat Brittle Tests
- Test JavaScript Interactions with a Real Browser
- Models, Part 1
- Active Record is for Database Access
- Active Model is for Resource Modeling
- The Database
- Logical and Physical Data Models
- Create a Logical Model to Build Consensus
- Planning the Physical Model to Enforce Correctness
- Creating Correct Migrations
- Writing Tests for Database Constraints
- Business Logic Code is a Seam
- Business Logic Code Must Reveal Behavior
- Services are Stateless, Explicitly-Named Classes with Explicitly-Named Methods
- Implementation Patterns You Might Want to Avoid
- Models, Part 2
- Validations Don’t Provide Data Integrity
- Validations Are Awesome For User Experience
- How to (Barely) Use Callbacks
- Scopes are Often Business Logic and Belong Elsewhere
- Model Testing Strategy
- End-to-End Example
- Example Requirements
- Building the UI First
- Writing a System Test
- Sketch Business Logic and Define the Seam
- Fully Implement and Test Business Logic
- Finished Implementation
- Reflecting on What We’ve Built
- Controllers
- Controller Code is Configuration
- Don’t Over-use Callbacks
- Controllers Should Convert Parameters to Richer Types
- Don’t Over Test
- Jobs
- Use Jobs To Defer Execution or Increase Fault-Tolerance
- Understand How Your Job Backend Works
- Sidekiq is The Best Job Backend for Most Teams
- Queue Jobs Directly, and Have Them Defer to Your Business Logic Code
- Job Testing Strategies
- Jobs Will Get Retried and Must Be Idempotent
- Other Boundary Classes
- Mailers
- Rake Tasks
- Mailboxes, Cables, and Active Storage
- Routes and URLs
- Beyond Rails
- Authentication and Authorization
- When in Doubt Use Devise or OmniAuth
- Authorization and Role-based Access Controls
- Test Access Controls In System Tests
- API Endpoints
- Be Clear About What—and Who—Your API is For
- Write APIs the Same Way You Write Other Code
- Use the Simplest Authentication System You Can
- Use the Simplest Content Type You Can
- Just Put The Version in the URL
- Use .to_json to Create JSON
- Test API Endpoints
- Sustainable Process and Workflows
- Use Continuous Integration To Deploy
- Frequent Dependency Updates
- Leverage Generators and Templates over Documentation
- RubyGems and Railties Can Distribute Configuration
- Operations
- Why Observability Matters
- Monitor Business Outcomes
- Logging is Powerful
- Manage Unhandled Exceptions
- Measure Performance
- Managing Secrets, Keys, and Passwords
- Authentication and Authorization
- Appendices
- Setting Up Docker for Local Development
- Installing Docker
- What is Docker?
- Creating a Docker Image to Work In
- Making Sure Everything Works
- Monoliths, Microservices, and Shared Databases
- Monoliths Get a Bad Rap
- Microservices Are Not a Panacea.
- Sharing a Database Is Viable
- Technical Leadership is Critical
- Leadership Is About Shared Values
- Leaders Can be Held Accountable
- Accountability Can be Implicit
- Colophon
- Setting Up Docker for Local Development