How to change URL after route match in Ruby on Rails - 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.

Related

Rendering page shows right page, but the URL doesn't include action

Can anyone tell me why when rendering a page in rails, for example:
render 'controller/action'
the url displays
/domain/controller
instead of
/domain/controller/action
The right page is shown, but the url is just the controller.
Is this an error that I have somewhere in my app?
for example if I did:
render 'users/show'
then the users show page would be displayed, but the url would be:
/mydomain/users
instead of what I would expect:
/mydomain/users/show
This is because Rails uses REST extensively for URL routing.
For eg:
When your application receives request as GET users/1, routes.rb will be referred to find out the corresponding controller and action.
Suppose, your route file contains
get '/users/:id', to: 'users#show'
Then, you request will be handle by show action of users controller.
For more information on routing in rails, refer to the Guide.
EDIT:
To answer your question, why doesn't the "show" action appear in the url,
Rails applications adhere to REST architectural constraints, called RESTful routes which are defined using a combination of HTTP verbs and URLs to controller action

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.

Get referrer URL with parameters in Rails

I have a site with the basic rails scaffold, when a user deletes a record the default action is to redirect to the home page. However I would like it to return to the list the user was just looking at.
Right now I'm using request.referrer which is technically getting the referral URL but the parameters are not included...
In my rails logs I can see "Started GET /books/book_preview?name=Hunger+Games"
But request.referrer only shows "https://x.x.x.x/books"
I have also tried .original_url and .original_fullpath but those return the path of the current page for the record "/books/HungerGames". I also tried URI(request.referrer).query to at least just get the parameters but that threw an error.
I would like to get the previous path with the parameters like: /books/books_preview?name=Hunger+Games
Also this list is a remote partial that is rendered through JS. You can't see the URL in the browser URL bar only when highlight over it or look in the rails logs. It doesn't even show up in the request when i looked through it using request.inspect.
Thanks in advance for any help! Have been stuck on this all day!
request.referrer
It will give you referral url with query params as well.
You're not getting the query string from the URL, according to this answer (& docs), you need:
request.fullpath #-> book_preview?name=Hunger+Games
--
As an aside, if you're using this as a lists page, it should be okay. However, if you're wanting to pull specific book records, you'd be better using a member route:
#config/routes.rb
scope "/books" do
resources :book_preview, only: :show, param: :name #-> url.com/books/book_preview/:name
end
This would give you the ability to return a specific object for that book, negating any need to hack the request path etc.

URL redirect in Rails 2

In my rails application, for some reason, I have to redirect my URL in to desired URL.
This is how my config setting the routes.rb.
map.connect 'sample/:action/:id.:format', :controller => 'test'
It redirects well when the url is http://example.com/sample. It goes Test controller index method.
When the url is http://example.com/sample/displayname?id=10, it goes to Test controller and searches for displayname method. Obviously it wasn't there, so I got the "undefined" error message.Here I want even though the URL is (http://example.com/sample/displayname?id=10) it quite enough to go Test controller's index method.
Also in the Address Bar I want to URL masking . If I hit http://example.com/sample/ it should redirect & in address Bar http://example.com/test.
How can i do this with Rails-2 application (Rails version 2.3.9)?
First, I don't recommend doing this. It's going against the conventions of how things are done in rails, and that tends to lead to pain.
(As for what I do recommend? Just structure your urls differently. If you do things the way rails makes easy, then you'll have fun using it. Otherwise, your life will be full of pain and suffering.)
BUT, if you really want to, it looks like you can't do regular expression routes in rails. I thought you could, but I see no signs that you can. What you can do, however, is...
def method_missing
index
end
Put that in the controller you want to have this behavior. It'll do what you want, but it also might hide other errors. In any case, don't say I didn't warn you. This seems like a bad idea...
As for the redirect, a before_filter in the test controller will do that.
before_filter :redirect_if_wrong_path
def redirect_if_wrong_path
if request.path =~ /\/sample/
redirect_to request.path.sub('/sample', '/test')
end
end

avoiding redirect

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.

Resources