# Resourceful Routing & "Default" or "Free" Functionality | Admins

- Canonical URL: https://wefunder.com/feed/174670
- Entity ID: wefunder:feed_item:174670
- Published at: 2024-08-12 22:06:40 UTC
- Updated at: 2025-07-13 05:12:21 UTC

## Author
Benjamin Garcia

## Subject
Admins

## Content
Note: While this is a technical topic, I'm trying to write this for a general audience. Please do read :) - The primary purpose of writing this down is so that I can link to it when planning new features. Since this will be a piece I reference continuously, I would love feedback so I can make it better. As I write this post, I'm maintaining a list of things I want to write about. My writing style has changed from loading bar to recursive outlining, meaning I jump all over. For that reason, it would be really nice to have multiple drafts at the same time, and be able to view them and edit them at will. That's functionality the new updates tool will have!But, I view this as "default" functionality. This isn't something that we're "adding to" the tool so much as the existing product was missing this critical default functionality. Implementing it at the beginning of development is remarkably straightforward and cost-effective.This post serves to introduce you to the concept of Resourceful Routing written for a both technical and non-technical audience, justify it's importance, and hopefully align expectations going forward. Even if you've never heard of the concept of resourceful routing, you're implicitly aware of it and have certain expectations around thing you should be able to do on a website (unsubscribe from emails, cancel a subscription, edit an address, etc.). These expectations can be modeled and understood through resourceful routing.tl;dr for developers at the bottomWhat is Resourceful Routing?Resourceful Routing is an overloaded term, and I'll use it in multiple contexts in this post. At its core, it allows you to quickly declare the seven common routes for a given resource, based on the CRUD operations (Create, Read, Update, Delete), fundamental to persistent storage systems. In simpler terms, when you perform an action on Wefunder, you are creating, reading, updating, or deleting one or more resources. Here are some examples:Make an investment (Click the Invest Button)Updates the Investment Resource to State 'Applied'Creates the Investment Contract ResourceReads the User Resource's "Full Name"Reads the ContractTemplate data to define the Template that will be createdCreates a Payment ResourceEtc.Follow a CompanyCreates a CompanyRole resource with role = 'follower'Unfollow a CompanyDeletes the CompanyRole resource role = 'follower' and user_id = current_user.idFounder Posts an UpdateCreate FeedItemRead CompanyRoles with role = 'follower'Creates FeedItemNotification Record for themResourceful Routing maps CRUD actions to URLs, plus three extra common routes: "Index", "New", and "Edit". For example, the route&nbsp;/admin/notable_investors&nbsp;in the admin/notable_investors feature:. Note the route is wefunder.com/admin/notable_investors, but the /admin is just a namespace and NotableInvestor is the resource.GET /admin/notable_investors&nbsp;=> Index (View Many)GET /admin/notable_investors/1&nbsp;=> Read NotableInvestor #1GET /admin/notable_investors/new&nbsp;=> FormGET /admin/notable_investors/edit&nbsp;=> FormDELETE /admin/notable_investors/4&nbsp;=> Delete NotableInvestor #4PATCH /admin/notable_investors/4&nbsp;=> Update NotableInvestor #4POST /admin/notable_investors&nbsp;=> Create NotableInvestor(Note GET / DELETE / PATCH are just HTTP methods. Don't worry about it.)Nested RoutesA related concept is Nested Routes, which expose the relationship between resources. For example, our manage page, is really the Investment Index page for a given company. And /company_slug/manage can be considered an alias for /company_slug/investments. Nested and namespaced routes are especially important for conflicts. I.e., we want a version of "Show FeedItem" to a founder that is different from the "Show FeedItem" to the investor that is reading it. Resourceful Routes reveal the relationships between resources through Nested Routes.Benefits of Resourceful RoutingWhile there are a bunch of benefits, they all share one vital thing in common:Rails is Optimized for Resourceful RoutingFor example:Consistency - When everyone follows Resourceful Routing conventions, it's really easy to find what you're looking for.Speed - Rails knows that Resourceful Routing is such a common requirement it offers lots of generators which writes boilerplate for you. You can create entire functioning Rails applications with just generators that create boilerplate for you, such as the first app I ever created: https://www.theodinproject.com/lessons/ruby-on-rails-installing-railsDefault / Free FunctionalityGiven Rails can generate much of the code, features mapped to singular resources (and correctly nested) are easy to implement. The Rails ecosystem, including helpers and gems, is designed to work with resourceful routing.When I say we get something "for free", I often mean that the cost of implementation is low because it maps closely to this exceptionally common abstraction.Practical Example: The Not So Resourceful /write and existing FeedItemsCurrently, users cannot draft multiple FeedItems simultaneously because there is no way to access them. FeedItems do not implement the Index view for writers, only readers. Additionally, we have both a&nbsp;/company_or_club_id/write&nbsp;and a generic&nbsp;/write&nbsp;endpoint, which adds complexity and overhead.We also implemented our nested resources really bizarrely, by offering both a /company_or_club_id/write, and generic /write endpoint. This generic /write endpoint adds complexity and overhead, because it's a very non-standard (and non-resourceful) page. It can either load an existing draft of one of the many clubs/companies you're a part of or create a new one and act as a new page, but it has to allow you to change which club/company you're writing for as a selection at the top. I'd argue no one even wanted /write to begin with either, and typically just results in writers posting their Updates in the wrong Company/Club, because it's so unintuitive. The /slug/write page is slightly better, because you don't have to worry about the nested resource, but you still have a single page for editing/creating new feed items and you cannot access other drafts or view them anywhere. There is no save for later, which is a common feature you would expect from a writing tool. But it also suffers from the existence of the generic /write page as there is also complexity and overhead on the page that specific that it is NOT the generic write page.Here is a quick example of the /write Method versus the new /updates page /edit method (these are responsible for the same thing):Generic /write:Versus the Updates#Edit Action:These do the same thing! Nuts!Not Always ThoughResourceful Routes are just a really common abstraction you can adhere to. But, not always! Sometimes, we don't want to have pages dedicated to individual resources. I.e. Like when someone "Likes" a FeedItem, we don't have a page like /feed_item/14/likes/100 so you can view the "100th like". That's silly.But, you should have all 7 by default, and remove the ones you don't need because they don't make sense, not because you're being careless. It's important not to overfit, but we certainly do not have that problem @ Wefunder.So Route Resourcefully!Resourceful Routing is a beginner concept that you learn early in your web development journey, but can be incredibly difficult to "get right". There are so many caveats and nuances to what I've said. For example, ID based routing is bad for SEO, sometimes you don't want to expose internal implementation details to a user, etc. But the general concept of default routing your resources with the 7 actions and creating different controllers depending on the relationship you're interested in authorizing based off (in the event of conflicts), go incredibly far in rapidly reasoning about new product.A tl;dr for developers (with examples)We're complicating our lives by not following convention https://guides.rubyonrails.org/routing.html#resources-on-the-web. If you've ever gotten confused by hundreds of controller callbacks, that's not a rails issue. That's a stuffing-everything-in-the-users-or-companies-controller issue. Here is a bite-sized introduction, note the conceptual compression: https://www.writesoftwarewell.com/rails-resourceful-routes/ . Notably for us, it would be a lot easier to debug investment controller callbacks if the investment controller was logically separated instead of having 40 different callbacks with different only and except calls:For example, we could have Investment::Reconfirmation, Investment::Confirmation, Investment::Contract, Investment::VipUpgrade, Investment::Eu, Investment::Rollover controllers.For the record, this is not normal. If you have to use more than 4 actions in an only: or :except, you should probably use a new controller. If more than 50% of your callbacks include conditionals, you should probably use a new controller, etc.