avoiding redirect - ruby-on-rails

Depending on the subdomain I want to call a specific controller.
What I currently do:
My page uses the subdomain to identify users like username.site.com. I get the username, look it up in the database and render the appropriate data in the UsernamesController.
the only exception to this is www.site.com or site.com . In that case another controller should be called. I currently do this by detecting the www or '' subdomain in `ApplicationController and then redirecting. Although I feel that a redirect is not in it's place here.
Someone has another approach?
Thanks

subdomains_routes allows you to define custom routes based on current subdomain.

Related

Multiple Domain pointing to single rails app displaying different content with the same url path

I have searched around the web and there are answers that have helped me abit, however I am still stuck, so here goes.
I a Rails 4 app that allows users to create a biography/blog and then access it using their own domain.
Users can choose from several pre-made website templates (main page, about me page, my hobbies page, etc...), and then they load up their content using a CMS. The content will then be displayed using their chosen template when visitors visit their domain.
Eg:
User 1:
Domain: www.user1.com
Template: Template A
User 2:
Domain: www.user2.com
Template: Template B
Desired Results
When a visitor visits www.user1.com, they will see the main page. When they click on "About Me", they will be redirect to www.user1.com/about-me. If a visitor visits the "About Me" page for user 2, they will see www.user2.com/about-me.
My question here is, how do I set this up?
Based on this answer: Rails routing to handle multiple domains on single application
class Domain
def self.matches?(request)
request.domain.present? && request.domain != "mydomain.com"
end
end
------in routes.rb------
require 'subdomain'
constraints(Domain) do
match '/' => 'blogs#show'
end
I know I can route a different domain compared to mine to a separate controller, however, I need to route it to different template controllers which can change at any moment (users can change templates at will).
I know I can set up a general controller that can read incoming requests, then based on the hostname, I can extract the appropriate template and then redirect the request to that template's controller (eg: Template1Controller), however the url gets messed up, becoming something like "/template/template1/index" or "/template/template1/about-me" which is very bad and ugly. Furthermore, it will be extremely tricky to handle paths specific to only some templates (Template A might have a "My Resume" page while template B might have a "Family History" page instead).
Is there a way to do this?
I have thought about a method where I have a single controller that will handle everything (without redirects) and then just calls render template1/index, but I think it is a bad way of doing it (different template might need different data in each page).
Btw, this will be hosted on EC2.
EDIT
What I am looking to implement is quite similar to this question Mapping multiple domain names to different resources in a Rails app , but unfortunately no answers then. Im hoping 5 years later, someone might know how to get this done.
Thanks!
I do this pretty simple with Heroku. It's probably not hard anywhere.
Once you have DNS set up.. the Rails layer can look like...
Create a before_filter in ApplicationController. before_filter :domain_check
In my domain_check method I just have if request.host ~= /whatever/ do this elsif ... elsif ... end
"do this" can be a redirect or a render or whatever.

How to change URL after route match in Ruby on Rails

I have been programming in Ruby on Rails for a while now, but never really dug deep into routing until recently. After reading a fair amount of documentation and googling, I haven't been able to answer this question.
How do you change a URL after a route is matched? To better explain this, let me set a scenario I'm trying to solve. The root of my website while testing is localhost:3000. My login page is localhost:3000/login. Once logged in though, I want the URL to read localhost:3000 again with no extension. The actual page name is dashboard and my route is as follows currently.
get 'dashboard' => 'user#dashboard'
This only matches when the URL is localhost:3000/dashboard, but I wan't to have cleaner URL like a lot of sites have. How is this achieved with Ruby On Rails? I want to avoid a javascript solutions or anything that is a workaround.
Any help or tips is greatly appreciated. Many thanks in advance.
I've provided the solution below, but I agree with max that your wanting to make a RESTful URL less meaningful is backwards. You should strive to alias a URL to make it more meaningful (e.g. from site.com/posts/34239482069472/ to site.com/posts/my-post-title).
The URL that appears in the address bar is an instruction to an app. When a user puts "site.com/dashboard" into the address bar, they're instructing the app to make an HTTP request get 'dashboard'. The Controller#action is a set of instructions the app executes when it receives that request. If you're following Rails naming convention then Users#dashboard will retrieve data and then by default render the view template at views/users/dashboard.html.erb. Understand this: you're not changing the URL for a given view, you're changing which view template is rendered by the Controller#action that is set for that url.
This means the Controller#action for your root_url (i.e. your root to: 'controller#action' in config/routes.rb) should render one view template if user is logged in and a different view template if a user is not logged in. Assuming root to: welcome#index, your controller action would look something like this:
app/controllers/welcome_controller.rb
def index
# db queries, logic, set #variables
if session[:user_id]
render "users/dashboard" # app/views/users/dashboard.html.erb
else
render "index" # app/views/welcome/index.html.erb
end
end
Note that if the view template you want to render corresponds to the controller, e.g. users_controller.rb action is rendering a view in views/users, then you only need to give the view name, otherwise you need to give a path (relative to app/views).
Why? /dashboard is a proper RESTful definition of a resource. In REST a route should have the same response independent of state. So having a radically different root page for a logged in user violates REST.
Also your users may want to access the index page as well the dashboard and you would be denying them that possibility.
These kind of URL micro-optimizations do not warrant hacking a bunch of state into your routes definitions.

Find out the last page the user was on

Is it possible for me to find out what the last route/page a user was on in one of my controllers? For example, if the user was on /home, then moved to /contact, is there was way for me to find out he was at /home within my controller?
Thanks
request.referer will give you the url which issued the request. If you need more informations like the path, you can use URI and write in your controller something like:
last_page_path = URI(request.referer).path

Generating secret URLs for a resource in rails

I've created a task management app that consists of lists and tasks. Users can only view their own lists and tasks. I would like to add the ability for a user to share a list if they like. Here are the steps I would like to accomplish:
User clicks a link from /list/show to share the list
User receives a secret URL to share: myapp.com/lists/1/23534512345234523 or whatever.
Secret URL redirects to a view other than /lists/show. Something like /lists/1/23534512345234523 which would be routed to /lists/secret_show or whatev.
Only users who have that url can see the information on that page.
Hope that is making sense. I imagine I would have to update the list record with a unique token to list.token. Then I would some how have to recieve the incoming URL and through a new action
lists#secret_share
def secret_share
...
end
Where I filtered for the list record by list.token and routed to secret_share. Then perhaps in the view I could simply restrict the view by the presence of the token in the URL.
Thoughts?
Whatever "secret URL" you hand out should not redirect to the real URL or you're going to create all kinds of opportunities for information leakage. It should be a strictly alternate URL.
Using routing for this seems like a good idea instead of using a separate controller. In your route you might want to pass an additional parameter to indicate this is a "secret" URL, like :secret => true where the value in question is something that cannot be submitted by the user to fake things out. User parameters are always strings, for instance, so using true should be a safe alternative.
This special parameter might disable access checking on your controller so that the page can be viewed by people that don't normally have access. You could also show a different layout using the layout method in your controller.

How do I add access controls to named routes in config/routes.rb?

I use require_admin! frequently in my controllers. It works great.
Now, I want to add named route like so:
# config/routes.rb
match "poniesandrainbows" => redirect("https://poniesandrainbows.com")
# ^sadly, not really a website, btw.^
How do I restrict access to that route? Is this possible? Obviously it redirects to a public URL, but I still want to keep the route private.
You cannot restrict access from routes.
The safest way to match "poniesandrainbows" with a controller where you can use require_admin! and then redirect them to the public url.
You can try to solve the problem on the front end. Maybe only show the link to admin users.
It won't stop other users to paste the link directly to their browser url though
That kind of functionality should be encapsulated in the controller. The router handles the plumbing of passing a request to the correct controller. It is the controller's job to correctly figure out how to process the request. In this cause, the controller would use the auth service (such as require_admin!) to determine if the user is allowed to be redirected or if they are doom to another fate.
It is actually possible although as the other posters mentioned very rarely a good idea. You can read about how in this blog post: (scroll down to the routes section)
http://collectiveidea.com/blog/archives/2011/05/31/user-centric-routing-in-rails-3/

Resources