Get referrer URL with parameters in Rails - ruby-on-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.

Related

How does Airbnb route each article?

I am making a website with Ruby on Rails, referencing Airbnb, and I found it difficult to make the following URL structure.
https://www.airbnb.com/help/article/767/what-is-the-resolution-center
In this URL, it seems that there is an article resource under help, so 767 is the ID of the article. In addition, after the ID, there is the name of the page in the URL.
scope '/help' do
resources :articles
end
By doing this, I was able to route until this part.
/help/articles/'page_id'
But I have no idea what to do from here.
I generated article model(title:string, content:text), and I am guessing that each article(title and content) is displayed according to the id.
Here's my questions.
How does Airbnb route page_name after the article ID?
In the case that the title and content in the article table are displayed, how do you put hyperlinks or internationalize the contents with I18n?
Also, please tell me if my guess is wrong in the first place, and tell me how Airbnb routes each article.
Thank you.
To tell Rails to accept request under URL like /help/article/767/what-is-the-resolution-center is actually very easy when you do use get instead of nested resources:
get '/help/article/:id/:slug', to: 'help_atricles#show', as: 'help_article'
Given the above URL, Rails would extract the id and slug from the URL and route the request to the show method of a HelpArticlesController.
That controller method could be as simple as:
def show
#article = HelpArticle.find(params[:id])
end
And to build such URLs you can use the help_article_path helper method defined by the as: 'help_article' part:
<%= link_to(
#article.title,
help_article_path(
id: #article.id,
slug: #article.title.parameterize
)
) %>
Read more about this routing method in the Rails Guides
Btw. I didn't use the slug part of the URL because it feels to me like it makes the URL look nicer and might be SEO relevant, but it feels useless from the application's point of view. You might want to use the slug part to identify the locale in which the article should be shown if you do not want to use the browser's locale setting.

URLs are UI in Rails 5

Came across this blog post recently and wanted to Incorporate its ideas into my Rails project - URLs should be short, human readable, shareable, and shorten-able. Specifically, I want to learn how to make URLs shorten-able with Rails. The example he gives is https://stackoverflow.com/users/6380/scott-hanselman and https://stackoverflow.com/users/6380 are the same URLs, the text after the ID is ignored and scott-hanselman will be added after navigating to the page. This improves readability and share-ability.
I would like the show action in my resource URLs to auto-add the page's <title> after the ID when navigating to the page but ignore it when the user pastes it into the search bar. This allows for malleable titles.
Example below. All these URLs should bring you to the resource with an ID of '1'
host/resource/1/exciting-blog-post
host/resource/1
host/resource/1/exciting-blog-post.html
host/resource/1/new-title-on-post
Edit:
The biggest difficulty I am having is editing the URL after the user submits it, ie transforming resource/1 to resource/1/name_column.
I have been able to redirect incorrect routes using the following in config/routes.rb - get "/events/:id/*other", to: redirect('events/%{id}')
Ok this was really tricky to figure out, didn't even know I had access to a lot of these parameters before. FriendlyID is not required, and not even capable of solving this issue.
The resource I'm using below is "events".
First edit your config/routes.rb to accept id/other_stuff
Rails.application.routes.draw do
resources :events
get "/events/:id/*other" => "events#show" #if any txt is trailing id, also send this route to events#show
end
Next modify event_controller.show to redirect if the URL is incorrect.
def show
#redirect if :name is not seen in the URL
if request.format.html?
name_param = #event.name.parameterize
url = request.original_url
id_end_indx = url.index(#event.id.to_s) + (#event.id.to_s).length + 1 #+1 for '/' character
##all URL txt after id does not match name.parameterize
if url[id_end_indx..-1] != #event.name.parameterize
redirect_to "/events/#{#event.id}/#{name_param}"
end
end
end
This will result in the exact same behavior as the Stack Overflow examples gave in the question.

How to redirect old url to new url in rails using just routes?

The old sitemap of my application has already been indexed to Google now. For some one visiting my rails app with old url shouldn't go to 404.
The old url looked like this
/search?sub_category=210
Now after making them friendly, it looks like this:
/search?sub_category=milling-and-drilling.
I tried redirecting it from controller but it causes too much issues on other things. Such as filters which are using the same params. Is there a way I can do it from routes file?
Instead of using redirect_to route_path(id) you would do redirect_to route_path(object.find_by_id(id).name)
How to redirect old url to new url in rails using just routes?
AFAIK (As far as I know), no. (if through params)
The main job of routes.rb is to determine what "code" will handle the request, particularly that which matches request.url and the request.method. It does not concern yet of the request parameters nor its values: these would be handled in the controllers itself. Although, you can route based on parameters (or any information about the "request") through a routes constraint
Alternative Solution:
Instead of finding by ID, now find by "Slug name or ID".
In your models, particularly in this specific example of yours, add something like:
class SubCategory < ApplicationRecord
# if you're using a gem for the "friendly" urls, you don't need this method, and just use theirs.
def self.friendly_find!(friendly_id)
# this may not necessarily be `name`, maybe `slug`? or depending on your case
find_by(name: friendly_id) || find(friendly_id)
end
end
And in your controllers, just replace wherever you're finding a record (maybe also to other models not just SubCategory as needed be), particularly in your search action:
def search
sub_category = SubCategory.friendly_find!(params[:sub_category])
end
NOTE: friendly_find! will raise an Error if no record is found.

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.

Rails routes and querystring

I am having troubles trying to define the correct route for a query coming from ember. The request appears like this:
GET "/users?id=1011
No matter what I try I always have the request forwarded to the index action, while it is intended for the show action.
I have tried many things, like
get "/users?id=", to: redirect('/users')
but nothing seems to work.
Can anyone explain to me what can I do and most important the reason behind it?
Thank you very much for your time!
GET /users?id=1011 always goes to index because Rails just sees the route as GET /users. The question mark denotes a parameter, which isn't part of any of your defined routes.
You can modify your index method to interpret the param, something like:
def index
if params[:id]
# call show, do something, whatever
else
# regular index action
end
end
In the case of retrieving just one user, it would be more common to route this to your show action as you originally intended. To accomplish this, do not pass the id as a query param, but instead as a slug segment /users/1011, which you can accomplish by declaring the following in your routes.rb:
get '/users/:id', to: 'users#show'
If you want to go full tilt then you might as well just declare users as a resource like so:
resources :users
Which will automatically wire up your index, show, update, destroy, etc. Throw Active Model Serializers in the mix and you can have Ember Data start talking to your API nearly "out of the box".

Resources