This is not a question of how to implement multi-tenancy. What I am looking for is the ability to optionally override the default application routes when required.
A simple case is that I have a route that generates a blog url like so:
http://[domain]/blog/post-slug
My configuration is blog/{slug}
However, some tenants do wish to call their blog "news". Although I can change all references blog in their views, I can't do it in the URL.
I would like a simple way of overriding these route configurations without changing the "core" codebase.
One thought I had would be to use named routes and then use this to swap out route configurations when the app starts. I should add that multiple tenants will not be using the same application instance, just the same codebase.
Thanks,
Ben
You can always add a route using a regular expression. There is also a great tool on figuring out what routes to add to get what you want.
http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx
What about if you have a filter that detects which type of user is accessing the action. If it is one who wants the word news, you can redirect them to a controller called news - which inherits all the functionality from blog.
I can't say I'm 100% confident, but I think it might work.
Related
I have a rather unique question that probably has a simple answer but I haven't been able to figure it out.
I am using rails 4.1 and creating an app that I want to accept urls that don't exist as part of a NFC tag registration process.
For example, let's say the app is located at example.com and I programmed an NFC tag with the url example.com/xyz123.
I don't want the rails app to spit out a 404 error but rather attribute that tag to the signed in User account and allow them to register that url to one of that users' personalized pages that they created.
I've dug into the docs on error handling but that doesn't seem to solve the problem and I can't seem to find where in the core API these requests are handled and how I might override them in the application.rb controller.
this is rather simple. just create a catch-all route
get '*path', to: 'tags#new'
the requested part will be params[:path]
i would recommend not having unscoped catch-all routes through. it's slow and a pita if you ever want to change your URL structure (you will want to do that at some point). always use some namespace www.some-url.com/t/xyz123
I'm building a rails3 application and at the moment I have the following line in my routes.rb file:
get "/:id" => 'tapes#show'
In other words, you can show a Tape using website.com/tapes/1 and also by using website.com/1
(I am also using friendly_id gem so the user sees in fact a friendly URL in the form of website.com/tapename)
Now, what I would like to achieve is to do the same thing for Users pages. So instead of showing a User page using website.com/users/alex I want to be able to also use website.com/alex.
Is there a way to implement this 'users' logic in routes.rb together with the existing 'tapes' rule and somehow set a priority?
So if someone accesses website.com/alex my app would search if there is a User record with id 'alex' and if none is found then look for a Tape with id 'alex'.
Could I use some kind of Advanced Constraints in routes?
Any ideas?
Many thanks for the help,
Alex
Rails would have no way to determine which controller you were trying to access. The only way that this would be possible, is if either:
you could determine which model it would resolve to based upon some regular expression on the name.
or
You knew that user names and tape names never conflicted, and were willing to suffer the cost of hitting the database to resolve the correct controller.
This is probably a bad idea for a number of reasons, it would have performance implications, it also doesn't conform to RESTful principles, and it would probably be confusing to users.
Background:
I'm building an app that lets users create their own website (e.g., mywebsite.alexlod.com)
Each website owner is affiliated with me, so I'll trust them to write their own rails code
Each website should have default controllers and views, except when one of these owners creates their own
Here's how I envision controllers working:
I'm thinking that what's in app/controllers/ will be the default, but when a file is specified in a <subdomain> top-level directory, that file will take precedence over the default.
Let me give an example. Let's say one of my website owners (foo.alexlod.com) wants to tweak app/controllers/photos_controller.rb. They should be able to create foo/controllers/photos_controller.rb whereby their controller is used instead of the default. I'm thinking the correct approach here has something to do with routes and the load path, but I'm new to Rails and Ruby and could use some guidance.
As for views, I would like them to work much the same. When a view or partial is defined in <subdomain>/views/, that view is used instead of the default located in app/views/.
I realize my plan here violates the default rails directory structure. But this approach has gotta be more simple than the alternative - case statements in each controller action. Unless there's an even better alternative?
I believe engines may be the way to go for what you want. That link is a little old but still should be applicable with Rails 3.1. Each subdomain's controllers and views can be placed in their respective engine folder.
Now, you just need to figure out which engine to load per request. That's the part I think may be the deterrent to your idea -- you don't want to be loading and unloading code all the time in production.
You may want to opt for a templating language like Liquid, in that case. That, however, gives a lot less control to the users.
I may have a partial answer for you as it sounds like you want to do something very similar to what I am doing for the mobile version of my site. After I identify that a user is mobile I add a mobile directory to the path to override any views that I have optimized for mobile. If the view doesn't exist in the mobile directory it defaults to the default view.
Here is what I did for views:
in app/controllers/application_controller.rb
before_filter :prepend_view_path_if_subdomain
def prepend_view_path_if_subdomain
unless pSubdomains.blank?
subdomain = request.subdomain.first
#This will add the subdomain view directory to the view path before the default
#Rails view directory and any views here will be picked up and rendered.
prepend_view_path 'app/' + subdomain + '/views'
end
end
Doing the same thing for controllers, however, is a little trickier due to routing. There is no prepend_controller_path method that is equivalent to prepend_view_path. Honestly I'm not sure how to approach this, you could use your case statement approach or possibly dynamically forward on the request to the subdomain controller (it if exists). I think it might be possible to add a before_filter to your controllers that evaluates each request much like I show above with views and then determines which controller should be used.
I also stumbled across this question: Rails 3.1 load controller from different path based on subdomain, not sure if it helps you or not.
Should urls have pluralized words in them or singular?
I personally like:
/user/register
Is this against the 'convention'?
I think it depends on the way you think what it is.
From the perspective of syntax, it seems to me /user/register make more sense. While from the perspective of resources, the /users/register make sense.
Is there more than one User in your application?
If so, the standard /users/register would be the conventional REST url scheme for registering a new user - assuming this results in a user being created.
You might consider the more convention /users/new unless "register" really is a different action than creating a new user somehow.
Yes, that's against the RESTful convention of /users/new. However, I don't see much of an issue with using more user-friendly URLs, especially if you preserve the original REST URLs too. In all my applications, the first thing I do is setup routes to /signup, /login and /logout.
Plural form controllers are the convention, because it makes the most sense, it implies /users/ will be an index of users etc.
However, the only time I would consider using a singular form controller name here is if, for example: your application is a little more closed, and users cannot view/modify each other (no index), and you were using this controller only to allow users to register and view/update their own details. In that case the singular form can be a sensible option, but it's still a matter of preference.
About 10 stackoverflow.com podcasts back Jeff mentioned that instead of wiring up his routes inside of the global.asax file he instead put them inside his controllers near the actions those routes would invoke.
How does one go about doing this?
Doesn't a route have to be registered before the controller it routes to is hit? Does he do it in the constructor? My mind is baffled by a chicken vs. egg issue here.
Check out this question.
I highly recommend you this approach. I'm using it with great success. :)
Basic idea - we are using attribute to setup a route for specific action.
In global.asax at app start we use reflection to initialize routes.
EDIT:
More precise link here.
EDIT2:
Not related to question but might be worth checking out (in case you haven't):
RESTful URLs from MVCContrib.