Rails Catchall Route (app allows username in URL) - ruby-on-rails

I have a simple blogging app where a user's username is part of the URL (i.e. myapp.com/username). How do I create a catchall route for all usernames not found. Currently, an invalid username causes:
NoMethodError in UsersController#show
undefined method `articles' for nil:NilClass
I'd like that to redirect to the 404 page.

Try this one
Write following function into your application controller
def not_found
raise ActionController::RoutingError.new('Not Found')
end
Then write down something as below into your users controller
User.find_by_username(params[:username]) || not_found
Hope, this will help you.

Looks like this is not the case in Production, which does indeed redirect to the 404 for invalid routes.

Related

'Render and/or redirect were called multiple times in this action' on devise

I am using devise and trying to redirect my user after sign up form to a specific template.
I've checked the docs about after_inactive_sign_up_path_for method but I am receiving an exception saying I am redirecting twice.
RegistrationsController < Devise::RegistrationsController
def create
super
UsersCreateJob.perform_later(resource.id) if resource.persisted?
end
protected
def after_inactive_sign_up_path_for(resource)
render template: 'devise/registrations/success'
end
Exception
AbstractController::DoubleRenderError in RegistrationsController#create
Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
As far as I understand, the after_inactive_sign_up_path_for method overwrites the one from Devise Registration Controller and redirect to my template, right? Where this other template is coming from?
after_inactive_sign_up_path_for is not meant to render a view. It's a path that will be used for redirect. You should just put a path to an action rendering'devise/registrations/success'.
The error you see is cause by the fact that the devise controller calls render/redirect and then you try to call it as well.

How to redirect with InvalidAuthenticityToken error

I've discovered that the handle_unverified_request method can be overridden in the ApplicationController to rewrite how Rails handles InvalidAuthenticityToken errors. By default the handle_unverified_request will raise the InvalidAuthenticityToken error. I've overridden this method like so
def handle_unverified_request
redirect_to '/422'
end
However, I'm using Airbrake which records errors that are raised on my Rails application. According to this answer, Rails can raise the error AND redirect the user to the 404 page. Does the same thing exist for the 422 page? I want to raise the InvalidAuthenticityToken and redirect the user to the 422 page. How do I do that?
ApplicationController.rb
protect_from_forgery with: :exception
rescue_from ActionController::InvalidAuthenticityToken, with: :rescue_422
def handle_unverified_request
raise(ActionController::InvalidAuthenticityToken)
end
def rescue_422
redirect_to '/422'
end
According to the link, you posted, Rails does not redirect the user to the 404 page, it renders 404 page instead. When InvalidAuthenticityToken error, Rails must render 422 page by default. It is done on Rack Middleware level.
If default behaviour is not what you want and you need redirect and Airbrake to log the exception, then you have to handle the exception and do the redirect AFTER! Airbrake logs it. I think that Airbrake logs exceptions on the Rake Middleware level, so you will have to somehow customize Rack Middleware's exceptions handler to get what you want. You will have to find out where Airbrake logs exceptions and make sure that your custom exceptions handler works after the logging.
Are you sure you want redirect, not render?

Error while redirect to path after user sign in using devise

I am developing a ruby on rails app and i want the user to redirect to specific pages after successful sign in with devise. I have the following code in my devise sessions controller:
protected
def after_sign_in_path_for(resource)
if resource.role == "User"
redirect_to user_home_path
else
redirect_to org_home_path
end
end
I have set up the controllers to display the page based on the redirect. However, the following error shows up after the sign in:
AbstractController::DoubleRenderError in Webs::SessionsController#create
Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".
I have searched, but with no luck. Please Help.
after_sign_in_path_for should just return the path but not perform a redirect, try changing your method like this:
def after_sign_in_path_for(resource)
if resource.role == "User"
user_home_path
else
org_home_path
end
end

How do I remove a subdomain from URL?

I followed the Railscast on adding subdomains to a Rails app, here, and everything is working great with the subdomains. Now I just can't figure out a way to link back to the root domain without a subdomain if the requested subdomain does not exist.
I've tried adding the following to my application_controller.rb file
redirect_to root_path(subdomain: false) if #city_or_state.nil?
where #city_or_state determines weather the requested subdomain is valid. The redirect_to goes back to the root, but does not remove the subdomain.
For example, if a user tries to go to invalid.domain.com they are redirected to the root, but subdomain is not removed.
I'm trying to get invalid.domain.com to redirect to domain.com
Ok, I got it. I had to use the following: redirect_to root_url(:host => request.domain)
When I tried root_path(:host => request.domain) it didn't work. Only works with root_url.
I found the answer on some comments from Daniel Kehoe here
When attempting to visit a domain that does not exist, the invalid subdomain is removed from the URL.
You can try this way i think it works!
In the application_controller.rb you can add a before_filter :validate_subdomain
Then you add this code to the controller:
private
def validate_subdomain
# #city_or_state must be initialized before this
if #city_or_state.nil?
redirect_to request.domain
end
end

Correcting invalid Resource Routes in Rails

One thing I noticed when working with nested resource routes in Rails is that it is technically possible for a user to visit a route where the child resource exists (and is therefore displayed correctly), but the id for the parent resource represents an object that is not actually related to the child resource.
For example, in the route users/:user_id/post/:id, the user could type in a route where :user_id represents a user who did not make the post corresponding to :id.
What would be the best way to fix this so that if the user visits an invalid URL, the server redirects the user to the correct URL?
I have already put some code in my controllers to handle this, but it's kind of awkward having to check the path in every controller action and then redirect the user to the appropriate url, especially since the URL helpers are different for every action.
(edit_user_post_path(#user, #post), new_user_post_path(#user, #post))
There has to be a better way, right?
You should have a before_filter running on all requests that makes sure the user is valid. If not, it will throw ActiveRecord::RecordNotFound and show the friendly 404 page.
Then grab the post based on the user however you need, whether in another before_filter or directly in the action. Base your post search on the user. My example below demonstrates doing this with another before_filter.
before_filter :find_user_by_user_id
before_filter :find_post
def show
# Use #post variable here however you need
end
private
def find_user_by_user_id
#user = User.find(params[:user_id])
end
def find_post
# This assumes you have an association set up as needed
#post = #user.posts.where(id: params[:id]).first
if #post.nil?
# Do whatever you need here
end
end
First of all you should know that the error wich is raised by ROR will display the message 'Sorry but the page you are looking for does not exist' on a production environment.
Therefor I would not be concerned about that. if you want to 'capture' the failure and quickly redirect to a safe area you might be interested in using the rescue method.
http://www.simonecarletti.com/blog/2009/12/inside-ruby-on-rails-rescuable-and-rescue_from/
have fun

Resources