In my Rails app, I have in the Application controller
respond_to :json
A controller that inherits Application controller responds with json like so in the action...
# Some code
if mission_updated.eql? true
render :json => {}
else
render :json => {}
end
However, whenever I run a rspec test in reference to the above action
it "should return appropriate response" do
post :update_unlocked_missions
parsed_body = JSON.parse(response.body)
parsed_body.should == {}
end
I'm returned with the following rspec error
ActionView::MissingTemplate:
Missing template api/v1/missions/update_unlocked_missions, api/v1/base/update_unlocked_missions with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee, :rabl, :haml]}. Searched in:
* "#<RSpec::Rails::ViewRendering::EmptyTemplatePathSetDecorator:0x007f9ea2903b00>"
My question is why is it going to the view when it should respond with json and how do I fix this?
Try testing with an action that's just render json: {}. If that works, the problem is probably something in mission_updated.
Related
I am trying to IP whitelist access to a particular file by placing a constraint on the file's route.
## config/routes.rb
get 'SOME FILE',
to: 'main#(function that renders the file as plain)',
constraints: <IP CONSTRAINT CLASS>.new
## (ip constraint class).rb
require 'ipaddr'
WHITELIST = %w(8.8.8.8/27).freeze
def matches?(request)
request && APPLE_IP_WHITELIST.reduce(false) do |match, range|
match || IPAddr.new(range).include?(request.remote_addr)
end
end
For IPs outside of the whitelist, a RoutingError is thrown. I try to handle the error by using a catch all route.
## config/routes.rb
get '*unmatched_route', :to => 'application#show_not_found', via: :all
## app/controllers/application_controller.rb
def show_not_found
render_error_status(404)
end
def render_error_status(status)
#status = status
template = case #status
when 400, 401, 403, 405
'application/errors/standard'
when 404, 422
'application/errors/with_block'
when 500
'application/errors/custom_500'
end
render template: template, layout: 'error', status: #status
end
Interestingly, when I try to access some nonsense route, like 'localhost:3000/asdf', the proper 404 page (application/errors/with_block.html.haml) is shown. However, when the whitelist RoutingError is handled, I get a
ActionView::MissingTemplate (Missing template application/errors/with_block with {:locale=>[:en], :formats=>[:text], :variants=>[], :handlers=>[:raw, :erb, :html, :builder, :ruby, :haml, :coffee]}. Searched in:
* "... /app/views"
* "... /.rbenv/versions/2.5.7/lib/ruby/gems/2.5.0/gems/kaminari-0.17.0/app/views"
):
tldr: how do I handle RoutingError resulting from a constraint failing?
Edit: it appears that formats: [:html] needs to added when calling render - but why is this necessary now and not the other times when render_error_status is called?
The main issue is with the request type, when the routing constraint fails Rails tries to find file with text format, see the error:
ActionView::MissingTemplate (Missing template application/errors/with_block with {:locale=>[:en], :formats=>[:text]
This is because you are requesting a text file from the route which cannot be returned because your routing constraint failed. So when the request type is text the error page should also be in that format. For example if I have an API where I send a JSON request and if there is an issue of permission and I provide HTML response then it will be of no use to the API. So the request and response format should be same in Rails when using the default conventions.
Your method should have different response types like this:
def render_error_status(status)
status = status
template = case status
when 400, 401, 403, 405
'application/errors/standard'
when 404, 422
'application/errors/with_block'
when 500
'application/errors/custom_500'
end
respond_to do |format|
format.html { render template, status: status }
format.text { render text: 'Not found', status: :not_found }
end
end
There are other options too available to do this like responding with HTML in case of text request but the standard Rails way is like this.
I randomly get this error when in production from certain IP Addresses on the root path. The rails app does not support the formats :formats=>[:gif, "image/x-xbitmap", :jpeg, "image/pjpeg", "application/x-shockwave-flash", "application/vnd.ms-excel", "application/vnd.ms-powerpoint", "application/msword"] so this error seems to be expected if a request is being made for them. I'm guessing that someone or some bot is trying to run an exploit against the site -- how can I redirect or route these kinds of requests back to the route path such that an error is not produced?
ActionView::MissingTemplate: Missing template front_page/index, application/index with {:locale=>[:en], :formats=>[:gif, "image/x-xbitmap", :jpeg, "image/pjpeg", "application/x-shockwave-flash", "application/vnd.ms-excel", "application/vnd.ms-powerpoint", "application/msword"], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :arb, :jbuilder]}. Searched in:
* "/app/app/views"
* "/app/vendor/bundle/ruby/2.0.0/gems/activeadmin-1.0.0.pre2/app/views"
* "/app/vendor/bundle/ruby/2.0.0/gems/kaminari-0.16.3/app/views"
* "/app/vendor/bundle/ruby/2.0.0/gems/devise-3.5.2/app/views"
File "/app/vendor/bundle/ruby/2.0.0/gems/actionview-4.2.4/lib/action_view/path_set.rb", line 46, in find
File "/app/vendor/bundle/ruby/2.0.0/gems/actionview-4.2.4/lib/action_view/lookup_context.rb", line 121, in find
File "/app/vendor/bundle/ruby/2.0.0/gems/actionview-4.2.4/lib/action_view/renderer/abstract_renderer.rb", line 18, in find_template
The full error is here
To achieve the result desired in your comment:
constraints :format => "html" do
resources ...
end
Or if you need more flexibility:
# application_controller.rb
ApplicationController < ActionController::Base
before_action :check_format!
...
def check_format!
unless request.format == :html
render :nothing status: :bad_request
end
end
...
end
But overall, I feel like this is all a ton of overkill...
Plus, it's very typical to see buckets of respond_to in controllers, because the normal behaviour is to try and serve up the any format. Otherwise, there would probably be tons of configurations and such.
Is there a way to do this for all controller actions unless explicitly stated
So when you say unless explicitly stated you're sort of swimming against the current.
I'm not sure that this will work for you, but perhaps something like:
def index
...
respond_to do |format|
format.html
format.all { render status: :bad_request }
end
end
I have Active Model Serializer setup and I have the create action to render show on successful creation of the record. If I go directly to a record by URL (/xyz/1) then it renders just fine using AMS. However when using the render method I get the following error:
ctionView::MissingTemplate at /contracts.json
==============================================
> Missing template v1/contracts/show, v1/base/show, base/show, application/show with {:locale=>[:en], :formats=>[:json], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby]}. Searched in:
I have a feeling if I create a show.erb.json file then the message will go away but then Active Model serializer will not be used.
Here is the line with that is causing the error:
render :show, status: :created, location: get_resource
If the get_resource method is needed please let me know.
i have a simple application to snooker league and i have a action add_player in LeaguesController. My client (AngularJS) call this action and i want to respond with json format using JBuilder. This working fine:
def add_player
...
render :json => #league.players.to_json(:only => [ :id, :firstname, :lastname, :max_break, :email ])
end
But when i delete this line and add:
respond_to do |format|
format.html
format.json
end
i have this error:
ActionView::MissingTemplate (
Missing template leagues/add_player,
application/add_player
with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder, :haml]}.
Searched in:
* "/home/daniel/SitesWWW/snookerLeague/app/views"
):
app/controllers/leagues_controller.rb:67:in `add_player'
Of course i have file add_player.json.jbuilder:
json.players #league.players do |player|
json.id player.id
json.firstname player.firstname.capitalize if player.firstname
json.lastname player.lastname.capitalize if player.lastname
json.email player.email
json.max_break player.max_break
end
So, what i should do?
Notice in your error message :formats=>[:html] this indicates to me it is trying to render add_player.html.erb and not your jbuilder template.
To verify this, try changing the calling code and append .json to the url which will force the format to be json.
You can also specify a default of json on your routes and not include it in the url:
resources :leagues, defaults: { format: :json } do
member do
post :add_player
end
end
see also: http://guides.rubyonrails.org/routing.html#defining-defaults
I figured I should finally write some tests for my rails app.
My controller is "UsersController". It doesn't have any HTML as I just have an iphone app sending a post in to a rails controller.
Here is my test:
require 'test_helper'
class UsersControllerTest < ActionController::TestCase
def test_create
# to http post
# /users
#user[email]=%#&user[password]=%#&user[password_confirmation]=%#
#post
post(:create, :user => {:password => "testpassword", :password_confirmation => "testpassword"})
end
Problem is that I get this error:
1) Error:
test_create(UsersControllerTest):
ActionView::MissingTemplate: Missing template users/new with {:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml], :formats=>[:html], :locale=>[:en, :en]} in view paths
So I guess it's trying to populate an HTML page? If so, I find this odd. I would think it would directly do the post to the controller. Can someone confirm that this "post" method tries and populates an HTML form?
If this is the case, how should I proceed in writing a test to directly send an HTTP post to the controller?
Thanks for any help
You can specify "format" to make it work:
post(:action, {'param1'=>'value1', 'param2' => 'value2', :format => 'js'})
Unless you tell it otherwise the post method assumes the requested content type is HTML. Typically the create action looks something like this:
#user = User.new(params[:user])
if #user.save
redirect_to posts_path
else
render :new
end
If the action fails it tries to render 'users/new', which doesn't exist, thus the error.
So there are a couple of issues here. It's not clear what content type is expected (XML?). The action is failing, but we can't see why. It might help to edit the question to show us what the controller action does.