Advanced Routing (resourceful, singular, nesting) #269

Closed
prajwalkman opened this Issue Mar 29, 2013 · 3 comments

Comments

Projects
None yet
2 participants

Hi,
Is there anthing in the pipeline for a more fleshed out routing system/library? The current one is pretty basic compared to say, Rails' Journey.

If there's nothing in the pipeline, I'm experimenting with a reusable library that can build a routes table in json, based on resource definitions.

Would the Sails team be interested in such a library?

My current plan is a definition syntax something like this(in coffee script):

Journey = require 'journey'

# nested resources under 'user' resource
actions = require './actions'
profiles = require './profiles'

# Multiple ways to define a resource

user_routes = Journey.resource 
                controller: 'users'
                singular: 'user'
                plural: 'users'

user_routes = Journey.resource 'user'

user_routes = Journey.resource
                controller: 'users'
                singular:
                  name: 'user'
                  routes:
                    'get /': 'show'
                  nested_resources: [
                    actions.plural
                    profiles.singular
                  ]
                plural:
                  name: 'users'
                  routes:
                    'get /': 'index'
                    'get /:id': 'show'
                    'post /': 'create'
                    'delete /:id': 'delete'
                  nested_resources: [
                    actions.plural
                    profiles.singular
                  ]

All these user defined resources would be nested under an internally implemented "root" resource.
Based on these definitions the lib would generate a routing table, possibly with additional data that could be used to generate route helper functions. It's one of the things that I think Rails really got right, and also the only thing I think Sails really lags in (apart from the Express version ;) )

This would also help decentralizing the routes and allow them to be split across files, like in Rails 4. What's your take on this?

Owner

mikermcneil commented Mar 30, 2013

Thanks for the compliments :)

Sounds like a neat idea-- can you dumb it down for this old boy? I don't actually come from a Rails background, and I'm not the best coffeescripter in the world either. If you could explain a use case to me, I think I'd have an easier time wrapping my head around it.

-mm

I'd love to.

Basically resource definitions in Rails have 2 forms: singular and plural. It uses inflectors to map both the singulalr resource (user) and the plural resource(users) to the same model (User). This is to reflect the 2 major types of associations in models: has-one and has-many. Consider the example of an Account model, which has-one Profile, and has-many Friend(s). When you nest them in URL Routing, it makes sense that you would point to the Profile controller's SHOW method with host.com/account/profile rather than host.com/accounts/:id/profiles/:id.

This is done in Rails by declaring the Account and Profile resource as singular resource, which would then map get /account to the SHOW action, and put /account to the UPDATE action. The controller of course will figure out what ID to update based on session variables. The Friends model is appropriately declared as a plural resource under Account, thus the INDEX action would map to /account/friends as you would expect.

The real power in Rails is being able to use both singular and plural forms of the resource together, thus allowing you to get really aesthetic and semantic URLs(this is currently not documented anywhere in Rails docs). Suppose you have some ADMIN accounts which need to be able to view any profile. It can be achieved with the following:

resource :account, only: [:show, :edit, :update] do
  resource :profile, only: [:show, :update, :edit]
  resources :friends, only: [:update, :show]
end

resources :profiles, only: [] do
  get 'search', on: :collection # This causes the URL generated to NOT include an :id parameter, ie, /profiles/search
  get 'preview', on: :member # (default)This causes URL to include an :id parameter, ie, /profiles/:id/preview
end

Such a complex routing system allows Rails to generate several routing helpers to greatly ease generating links. Creating a link to the account's profile is a simple method: account_profile_path and for friends: account_profile_friends_path. It also takes a parameter, which is some model object to generate URL which require IDs. Ex: account_friends_path(@some_friend_model_object).

That's the gist of why such a complication resource definition system is very helpful for large projects. My proposition was to abstract this away into a library, which generates a single object containing all information necessary for generating routes, mapping resource names to models and controllers, and nesting information. This object can be consumed by Sails, as well as a client side MVC(through JSON), to generate routing information as well as route helper functions like described above.

Owner

mikermcneil commented Apr 14, 2013

@prajwalkman Sorry to get back so late. I see! I think this is a great issue to tackle once we have core association support built in to the database.

As for inflections, I've struggled with this feature in other MVC frameworks (namely CakePHP) and I'm pretty against it-- just ended up complicating things imo. Of course, you can always use plural routes, and I'd be happy to have built-in inflection support, I just wouldn't want it to be enabled by default.

Everything else makes sense. Thanks for taking the time to explain this for me! I'll reapproach this in July when I've go some time to finish up associations.

Put this together today: https://github.com/balderdashy/sails/wiki/roadmap

-mm

mikermcneil closed this Mar 7, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment