how do you determine if request.referrer matches a Rails restful path? - ruby-on-rails

As we know from this post, in Rails, you can get the previous url by calling
request.referrer
But how do you check if the previous url matches one of the restful paths in
your Rails application?
By restful paths, I mean paths provided by Rails, such as,
books_path
book_path(book)
edit_book_path(book)
Of course I can do a regular expression string match on request.referrer, but I think it's a bit ugly.
One particular case, in my application, is that request.referrer can be
"localhost:3000/books?page=4"
and I want to it to match
books_path
which returns "/books"
In this case, how can I check if there's a match without doing regular expression string
match? (if this is at all possible)
Thanks
P.S. I have tried regular expression string match, and it works. I just thought there might be a better way in Rails.

You could extract the path portion of the request.referer using the following:
URI(request.referer).path
You can then use Rails.application.routes.recognize_path to check if path maps to a controller and action, e.g.:
my_path = URI(request.referer).path
# => /books
Rails.application.routes.recognize_path(my_path)
# => {:action=>"show", :controller=>"books", :page=>"4"}

Though not certain of what you want to do with that, pretty sure rails support better ways of controlling redirects. Nevertheless, I guess this is what you are looking for:
request.referer == books_url(page: params[:page])
UPDATED:
This way, even if there's no params[:page]. This would still work properly.

Since recognize_path was deprecated, this is another way of doing it:
Name your route in your routes config using the as keyword:
get 'foo/bar' => 'foo#bar', as: :foo_bar
Then you can do the check like this:
if URI(request.referer).path == foo_bar_path
do_something()
end

Related

Rails `redirect_to "/#{session[:user_id]}"` puts '#_=_' in my URL

I am trying to a simple redirect in rails using redirect_to "/#{session[:user_id]}". For some reason it's redirecting to something like: '/2#='. I can User.find(session[:user_id]) just fine, so where are the extra characters coming from and how do I sanitize them (remove them)?
You'll be much better using the Rails path helpers -
redirect_to user_path(session[:user_id])
This of course considers you have a users path:
#config/routes.rb
resources :users, path: ""
The problem you'll have is because you're trying to render a naked link, I believe Rails will treat it as a get request, and consequently want to append any params to the URL for you (hence the =)

Rails catch-all/globbing routes

I am using rails 3.0.14, and I am constructing routes.rb using the resourceful style. I'd like to have a wildcard route that catches all requests that do not match to any route stated.
What's the appropriate way to construct such a route?
put
match '*path' => 'your_controller#your_action'
at the end of the routes.rb file. This is important, since the routes are stepped through top down.
See also http://guides.rubyonrails.org/routing.html -> 3.10
For Rail 4, you need to specify the request type:
match "*path", to: "application#custom_action", via: :all
As others have said, put this at the very bottom of your routes file.
It is not mandatory to use exactly "path" in the match '*path' statement. You can set a whatever token there:
get "*string1"
or
get "*string2"
Rails will assign your real HTTP-query to the param named after your token, example:
get "*user" => "users#show"
in console:
Started GET "/john" ....
Processing by UsersController#show as HTML
Parameters: {"user"=>"john"}
You can use more than one asterisks, say get "*id*user". But in this case you will get some unpredictable result, because Rails processes 2 or more asterisks "in an intuitive way" - for more info see http://guides.rubyonrails.org/routing.html#route-globbing-and-wildcard-segments
In addition to #steel and #awenkhh, I recommend adding the following to that route's controller action
respond_to do |format|
format.html
# other formats you already support
format.all { render text: '' }
end
Otherwise, you'll wind up with some ActionView::MissingTemplate: Missing template errors for formats that you weren't expecting.
[rant]Particularly helpful for those people trying erroneous attack vectors around /wp-admin/css/wp-admin.css and the like. I seem to get about 100 requests for /wp-admin/* a day, from super annoying people who apparently would like me to get a more expensive Rollbar account plan.[/rant]

Custom path generator

I thought I knew how to override a path helper, but I'm not getting my expected behavior.
I tried adding something like this to my ApplicationHelper:
def post_path(post)
"/posts/#{post.id}/#{post.url}"
end
But for some reason, in one of my controllers when I try to use post_path(#post) it just returns the full url, something like /posts/4faddb375d9a1e045e000068/asdf (which is the current url in the browser) rather than /posts/4faddb375d9a1e045e000068/post-title-here.
In my routes file:
get '/posts/:id/:slug' => 'posts#show', :as => 'post'
The strange thing is if I use post_path(#post, #post.url), it works correctly. And if in a view I use post_path(#post) it works correctly. (#post.url returns the url friendly title)
In case you can't tell, I'm trying to eventually get the behavior similar to stackoverflow's where the url contains the id and a slug at the end and if the slug doesn't match the model with the given id, it'll redirect to the correct url.
What I'd try would be to put the whole def post_path in the application_controller.rb and make it a helper with helper_method :post_path. You'll get the best of both worlds.

Rails 3 change path to url

I am passing a path as a parameter, so params[:path] would be name_path(:username => #user.name (I want to pass it as a path and not a url, so putting name_url in the params isn't what I want).
Since you can only use redirect_to with a url, I need to change the path to a url before I can use redirect_to. How would I do this?
I found this method here
def path_to_url(path)
"http://#{request.host_with_port_without_standard_port_handling}/#{path.sub(%r[^/],'')}"
end
But, this was written in 2008, and I want to know if there is a better way in Rails 3?
Updated copy from original path to url post btw: also works on Rails 2
# abs or /abs -> http://myx.com/abs
# http://grosser.it/2008/11/24/rails-transform-path-to-url
def path_to_url(path)
"#{request.protocol}#{request.host_with_port.sub(/:80$/,"")}/#{path.sub(/^\//,"")}"
end
I think you can use a redirect_to with a path as long as its a route defined in the routes file for the current application. Thats seems to be the case from your question.
ie, name_path(:username => #user.name)
So the following should be valid.
redirect_to params[:path]
I ended up using
def path_to_url(path)
"http://#{request.host}/#{path.sub(%r[^/],'')}"
end

Why is Rails encoding slashes for catch all (splat) routes?

When using a catch all route the URLs have the forward slash encoded as %2F which means I can not lookup a record using request.path
map.document '*path', :controller => 'documents', :action => 'show'
Page.find_by_permalink('/blog/my_first_post') # Record found
Page.find_by_permalink('blog%2Fmy_first_post') # Record not found
Firstly why is this encoding happening, and secondly is there a way to turn it off?
PS. I know I could decode request.path before using in the find but I would prefer a pretty URL.
try renaming your glob variable to request_path and use params[:request_path], I do a similar thing and I've never had this problem. however, I believe I snip off the end and search by slug, then do a comparison of the path to what I believe it should be.

Resources