Get model or 404 on Rails - ruby-on-rails

Is it possible to use a function as get_by_id_or_404 on rails. For exemple, in my controller i use :
#destination = Destination.find_by_id(params[:id])
if the id isn't set or the destination not found, how can I ask Rails to redirect to a 404 page?
Thank you!

In production mode, Rails automatically rescues the ActiveRecord::RecordNotFound exception by rendering the 404 error page.
Simply use the bang version of the finder that raises ActiveRecord::RecordNotFound when no result is found.
#destination = Destination.find_by_id!(params[:id])
However, in your case there's no reason to use the find_by method. Simply fallback to find.
#destination = Destination.find(params[:id])

This is from the guide:
You can specify an exclamation point (!) on the end of the dynamic finders to get them to raise an ActiveRecord::RecordNotFound error if they do not return any records, like Client.find_by_name!("Ryan")
When this happens, Rails will render the 404 page for you. Also, simply use find as a shortcut for find_by_id:
#destination = Destination.find!(params[:id])

I think in production, it will raise the error and display the 404 or 500.

Related

Do I need to generate a controller for a Ruby on Rails Controller call?

I'm setting a session variable to a user's geographical state. I have to use a session variable because I run code on the server specific to that user on page load and I need to know where they are. This code is set up to just update the session variable.
states_controller.rb
class StatesController < ApplicationController
def loc
session[:location] = params[:location]
end
end
routes.rb
post "states/loc" => "states#loc"
The code routes properly and the session variable is updated.
However, when the process is complete I get a 500 error in the console "Missing Template" in the views directory. I haven't seen any tutorials tell users to call the command "rails generate controller" and I'm in the unique situation where I can't call this command.
What possible side effect are there to ignoring this 500 error?
*I'm running an older version of ruby and rails.
What possible side effect are there to ignoring this 500 error?
Each request is crashing your rails server. Thats not good. Since it means that some cases it may have to restart after every failed request - that eats resources like Homer Simpson at a buffet.
Your app should not be raising uncaught exceptions that cause 500 errors - thats just decent professional practice.
So how do I fix it?
Simple, if you don't want the default behavior of rendering a view tell rails to do something else:
class StatesController < ApplicationController
def loc
session[:location] = params[:location]
head :created
end
end
This sends an empty response with the 201 - CREATED http header.
See Rails Guides - Layouts and Rendering in Rails

Rails.application.routes.recognize_path error with undefined method authenticate

In my application_controller.rb I have a line
# Get the previous url string nicely.
previousPath = Rails.application.routes.recognize_path(request.referrer)
But I get this error on that line
NoMethodError (undefined method `authenticate?' for nil:NilClass)
Which seems like something to do with devise.
But when I do include Devise::TestHelpers, I get env is not defined or something, which doesn't seem like a good solution in any way possible.
Any ideas on how to solve this without needing me to catch errors or regexp to split the path?
This issue may be due to route path which is written in routes by default as and when the application loads first, so join the string to the url you get from request.referrer.
ie, url = request.referrer + "controller_name"
previousPath = Rails.application.routes.recognize_path(url)

Googlebot receiving missing template error for an existing template

In the last couple of days, we have started to receive a missing template error when the google bot attempts to access our main home page (welcome/index). I have been staring at this for a couple of hours and know that I am just missing something simple.
A ActionView::MissingTemplate occurred in welcome#index:
Missing template welcome/index with {:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml, :haml], :formats=>["*/*;q=0.9"], :locale=>[:en, :en]}
But the template does exist (index.html.haml). If it didn't no one could access our home page.
Here is some additional environment information:
* REMOTE_ADDR : 66.249.72.139
* REMOTE_PORT : 56883
* REQUEST_METHOD : GET
* REQUEST_URI : /
* Parameters: {"controller"=>"welcome", "action"=>"index"}
Any insights you have would be greatly appreciated.
These errors are coming from the way GoogleBot formats its HTTP_ACCEPT header. While valid (see W3 reference), it adds a q=0.6 (last figure may change) which is used as a separator. Since there is no other media type specified, this q=0.6 is not necessary and I assume this is why Rails doesn't treat the header correctly.
(It seems to depend on Rails version. On Rails 3.0.12, it raises a MissingTemplate exception.)
Adding the following code from a previous answer to the concerned controller is not sufficient: it responds with an error 406.
respond_to do |format|
format.html
end
To make this work under Rails 3.0.12 and have something returned to the GoogleBot (better than a 406 error), you need to add this code which sets the request's format to html as soon a */*;q=0.6-like HTTP_ACCEPT is detected (Rails load the header value into request.format).
# If the request 'HTTP_ACCEPT' header indicates a '*/*;q=0.6' format,
# we set the format to :html.
# This is necessary for GoogleBot which perform its requests with '*/*;q=0.6'
# or similar HTTP_ACCEPT headers.
if request.format.to_s =~ %r%\*\/\*%
request.format = :html
end
respond_to do |format|
format.html
end
While working, this solution needs the code to be added to any controller action you want to be indexed by the GoogleBot, what is really not DRY!
To fix this issue once for all, I implemented a small Rack middleware which does even better: it checks the request's HTTP_ACCEPT header, and will replace any header matching */*;q=0.6 (the figures can vary) by the common */*. This is even better because since the q=0.6 has no meaning if it is not followed by another media type, this change of the header doesn't change its meaning. We don't force Rails into any given format, we just tell it any will do in a way it can understand.
You can find the middleware, the loading initializer and an integration test in this gist.
Gem version here:
https://github.com/ouvrages/rails_fix_google_bot_accept
I am also getting the same, I did some investigation and came to the conclusion it is a 'bug' in Rails. */*;q=0.9 is the value of the HTTP accept parameter. I'm not exactly sure what is going on, but in Rails 3.0 this works. In Rails 3.1 it returns a 500 response, and in Rails 3.2 it returns a 406 response.
Update:
There is an open bug regarding this issue. One workaround is to set this new option in Rails 3.1:
config.action_dispatch.ignore_accept_header = true
However... if you serve any pages other than HTML you'll need to rely on the extension to denote the type (e.g. /users/1.json) instead of accept headers.
The solution to the problem is to specify the format in your action.
Up until now, I had simply had the following in my index action
def index
end
Once I inserted a respond_to block
def index
respond_to do |format|
format.html
end
end
I stopped getting the missing template errors.
the interesting part in the error that you posted is :formats=>["*/*;q=0.9"]
the rails-app tries to find a template for the format "*/*;q=0.9" which is not going to work.
i guess that google is somehow using this as a format query parameter like welcome?format=*/*;q=0.9
afaik latest rails versions will just render a 406 in those cases.

Custom 404 action in Rails

Default Rails will render 404.html, then it thinks an error 404 is appropriate. However, I want make it by custom page. Please suggest the proper way do it.
This answer was surprisingly hard to find.
If you want a static page, edit 404.html. Done.
If you want a dynamic page, then:
in config/routes.rb:
match '*not_found', to: 'errors#error_404' unless Rails.application.config.consider_all_requests_local
Comment out the unless clause to test the 404 page on local dev machine.
Generate a bunch of files:
rails generate controller errors error_404
Edit views/errors/error_404.html.erb to customize.
This works for Rails 3.1 and 3.2.2.
You could use render_404 monkey patching.
Or, you could set a default route at the bottom of your routes file that goes to an action that returns a 404 status code.
Ideally if you do not want any custom code in your 404 you can just edit the static 404.html, which is easiest.
Depending on what you need, our gem might help: http://github.com/hedgeyedev/snow

rails: displaying a user friendly message for a routing error in rails

i am working in rails 2.3 on mac osx leopard.
every time i type a url that does not exist in a rails application i get the following error
Routing Error
No route matches "/whatever_i_typed" with {:method=>:get}
this is find for development, but i was wondering how i can make sure users see a friendlier 'oops! not found' page. i was thinking about doing a begin...rescue block but i didn't know where to put it, not did i know the error code (i.e ActiveRecord::RecordNotFound)
thanks!
yuval
This error will never appear in production. Instead, users will see the public/404.html page.
To try this out on your localhost, put passenger/mongrel into production mode. Override the local_request? method on your ApplicationController like so:
class ApplicationController
def local_request?
false
end
end
If you'd like to experiment with dynamic behavior you can check out the rescue_from class method on ActionController.
How about
map.connect '*url', :controller => "not_found"
as a last routes.rb entry? I think it should do the trick, shouldn't it?
I found the below url helpful for Rails 3.0.. users.
http://techoctave.com/c7/posts/36-rails-3-0-rescue-from-routing-error-solution

Resources