I'm using RSpec to test my views. I want to test that the view for the edit action contains a field (or text) "Director". It's choking on render. Here's my code:
# spec/views/movies/edit.html.haml_spec.rb
require 'spec_helper'
describe 'movies/edit.html.haml' do
it 'displays \'director\' field on edit page' do
render
expect(rendered).to have_content("Director")
end
end
On running this I get the following error:
Failure/Error: render
ActionView::Template::Error:
No route matches {:action=>"show", :controller=>"movies", :id=>nil}
My understanding is that convention over configuration means that render without any arguments should render the intended view app/views/movies/edit.html.haml I don't know why it's looking for the route to the action show. That route does exist, though it has nothing to do with this spec.
I've tried a number of permuations of arguments to render with no luck:
render :edit
render action: :edit # is this even valid?
render :action => :edit
render "edit"
render "edit.html.haml"
render action: "edit"
render action: "edit.html.haml"
render :action => "edit"
render :action => "edit.html.haml"
All the above produce one of two errors:
ArgumentError:
You invoked render but did not give any of :partial, :template, :inline, :file or :text option.
OR
ActionView::MissingTemplate:
Missing partial /edit, movies/edit with {:locale=>[:en], :formats=>[:html, :text, :js, :css, :ics, :csv, :png, :jpeg, :gif, :bmp, :tiff, :mpeg, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json, :pdf, :zip], :handlers=>[:erb, :builder, :coffee, :haml]}.
I'm not trying to render a partial, I'm trying to render the full view. Am I using the convention incorrectly, or using render incorrectly?
Edit1: I don't think it's a partial. There is a view at app/views/movies/edit.html.haml. I may not properly understand what a partial is.
Edit2: I tried the same spec for the new action and it seems to run fine (fails when the text is not there, passes when the text is there). Does this mean I need to load the edit view as a partial, or do I need to give it dummy data for #movie? And why is edit a partial?
For anyone else looking for something similar, you should be assigning a movie model for the view to render.
Something like the following should work:
describe 'movies/edit.html.haml' do
let(:movie) { Movie.create(movie_params_go_here) }
it 'displays \'director\' field on edit page' do
assign(:movie, movie)
render
expect(rendered).to have_content("Director")
end
end
Related
actually i use rails for my REST API, and i need transform my object to json but when i try i got this error:
<h1>Template is missing</h1>
<p>Missing template firms/show, application/show with {:locale=>[:en], :formats=>[:html, :text, :js, :css, :ics, :csv, :png, :jpeg, :gif, :bmp, :tiff, :mpeg, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json, :pdf, :zip], :handlers=>[:erb, :builder, :arb, :jbuilder]}. Searched in:
* "/Users/allan/Desktop/Work/back/app/views"
* "/Library/Ruby/Gems/2.0.0/gems/activeadmin-0.6.0/app/views"
* "/Library/Ruby/Gems/2.0.0/gems/kaminari-0.16.3/app/views"
* "/Library/Ruby/Gems/2.0.0/gems/devise_invitable-1.5.5/app/views"
* "/Library/Ruby/Gems/2.0.0/gems/devise-3.5.4/app/views"
</p>
This is my code
def show
firm= Firm.find_by_subdomain(params[:subdomain])
if firm.present?
respond_to do |format|
#firm = firm
format.json { render :json => #firm.to_json }
end
end
end
I hope someone here can help me :)
Solve:
def show
render json: Firm.find_by_subdomain(current_subdomain)
end
thank you
Template missing means that you asking for a html view, not doing a json request.
If you want to always return json format regardless of format param, do this:
before_action :set_default_response_format
protected
def set_default_response_format
request.format = :json
end
#source: Rails 4 - How to render JSON regardless of requested format?
Try to add .json at the end of you query when querying your route. Without this, it will try to render html and it will go search for view file that might not be present in your case.
I'm rendering a js.erb partial which enables ajax functionality to like/dislike a restaurant dish. I recently came across the around_action callback and figured yield would help perform the controller action first and render the template second. Unfortunately I'm getting a 500 (Internal Server Error) due to the respond_to never getting called.
The respond_to method works if I place it inside the controller action but not inside the callback. What am I doing wrong?
class DishesController < ApplicationController
before_action :set_dish_and_restaurant
around_action :render_vote_partial
def like
#dish.liked_by current_user
end
...
private
def set_dish_and_restaurant
#dish = Dish.find(params[:id])
end
def render_vote_partial
yield
respond_to { |format| format.js { render "vote.js.erb" } }
end
end
Console Error
ActionView::MissingTemplate (Missing template dishes/like, application/like with {:locale=>[:en], :formats=>[:js, "application/ecmascript", "application/x-ecmascript", :html, :text, :js, :css, :ics, :csv, :vcf, :png, :jpeg, :gif, :bmp, :tiff, :mpeg, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json, :pdf, :zip], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :jbuilder]}. Searched in:
* "/app/views"
* "/Library/Ruby/Gems/2.0.0/gems/devise-3.5.1/app/views"
):
app/controllers/dishes_controller.rb:29:in `render_vote_partial'
Okay so with your stack trace it is pretty clear what is happening. You have to understand the default rails behavior of convention over configuration.
As soon as you call yield, your controller action gets called. Now all controller actions by default look to render views with the same name as action, once the actions are done executing.
So calling render_to after yield doesn't make any sense, as controller action you yielded to has already called its render :)
In any case what you are trying to do is a bad design pattern, rendering views should be left to actions
Update
Theoretically speaking : As you wish to keep things DRY you could render the same view after each action by creating a common method calling it after every action. However, think about it, your render will have one line, and calling that same method will need one line too :) so where's the DRY.
In short, DRY should not be over done at the cost of simplicity. In my opinion KISS trumps DRY :)
I'm trying to render a liquid template that is stored in the database.
Here is my 'show' action in the controller:
def show
#organization = Organization.find_by_subdomain(request.subdomain)
#template = Liquid::Template.parse(Template.find(#organization.current_template).body)
#page = #organization.pages.find(params[:id])
respond_to do |format|
format.html { render #template.render('page' => #page), :template => false}
format.json { render json: #page }
end
end
However, when I visit the page, I get a "Template is Missing" exception with the following error (note that "testing testing" is the body attribute of the page object, which is currently the only thing being rendered in the template):
Missing template /testing testing with {:locale=>[:en], :formats=>[:html], :handlers=>[:erb, :builder, :coffee, :haml]}.
Searched in: * "/Users/ashercohen/Documents/Rails/Vocalem-Rails/app/views"
* "/Users/ashercohen/.rvm/gems/ruby-1.9.3-p194/gems/twitter-bootstrap-rails-2.1.1/app/views"
* "/Users/ashercohen/.rvm/gems/ruby-1.9.3-p194/gems/devise-2.1.2/app/views"
Why is it trying to find another template, when I've specifically pass the :template => false argument? Is there something I'm missing here? I'm trying to bypass using any template files, as it seems like they shouldn't be needed here (though am not strongly opposed if I am wrong).
Because render almost always takes a filename, while #template.render('page' => #page) contains the plain html. You should invoke render like this:
render :text => #template.render('page' => #page), :content_type => :html
Is it possible to render a js.erb in response to an AJAX request without using the respond_to method?
I am asking because of a few reasons:
I will only be making AJAX calls to my controllers;
I will not be supporting any other content types (i.e., :html, :xml, etc.); and
I want to be able to render a different js.erb file, not one named the same as the controller method (i.e., different.js.erb)
Here is some code to serve as an example.
app/views/posts/awesome.js.erb:
alert("WOOHOO");
PostsController#create
def create
#post = Post.new(params[:task])
if #post.save
render :partial => 'awesome.js.erb'
end
end
When the create method is called via AJAX, Rails complains about a partial missing:
ActionView::MissingTemplate (Missing partial post/awesome.js, application/awesome.js with {:handlers=>[:erb, :builder, :coffee, :haml], :formats=>[:js, "application/ecmascript", "application/x-ecmascript", :html, :text, :js, :css, :ics, :csv, :xml, :rss, :atom, :yaml, :multipart_form, :url_encoded_form, :json], :locale=>[:en, :en]}. Searched in:
While Kieber S. answer is correct, here is another method that I think would be valuable for those who want to support the "conventional" method of creating js.erb files.
Instead of using render :partial use render :template. The caveat here, however, is that the search path for the template isn't automatically scoped to the name of the controller (i.e., app/views/posts). Instead, Rails starts at app/views/. So to reference the "template", you need to add the subfolder you want to look into, if it isn't in the root. In my case, I had to add posts.
def create
#post = Post.new(params[:task])
if #post.save
# using :template and added 'posts/' to path
render :template => 'posts/awesome.js.erb'
end
end
The benefit here is that if you should so happen to want to use the respond_to method and follow convention, you wouldn't need to rename your js.erb by removing the underscore.
Partial files need to be named as with a underscore.
Try to rename your partial to app/views/posts/_awesome.js.erb
In a scaffolded Rails 3, when 'update' method fails to save, the logic is already there to redirect back to the edit page.
we modified the scaffolded method to do some custom validation logic (after update, but before we render the resulting view
respond_to do |format|
if #thingy.update_attributes(params[:thingy])
if #thingy.found_warning_101
WHAT GOES "HERE" TO REDIRECT TO EDIT PAGE
AND HAVE THE DEFAULT SCAFFOLDING ERROR HANDLING SHOW "WARNING 101"?
THIS DOES NOT WORK, GIVES MISSING VIEW ERROR, DOESNT FIND EDIT VIEW:
format.html { render :action => "edit", :notice => "WARNING 101" }
format.xml { render :xml => #things.errors, :status => :unprocessable_entity }
return
end
format.html { redirect_to(#thingy, :notice => "thingy was successfully updated.") }
format.xml { head :ok }
else
format.html { render :action => "edit" }
format.xml { render :xml => #beep.errors, :status => :unprocessable_entity }
end
We tried (above) to simply copy the same code that scaffolding creates for the case that .update_attributes fails (followed by return) but we get a missing view error:
Missing template thingys/update with {:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml, :haml, :voice], :formats=>[:html], :locale=>[:en, :en]} in view paths
I don't really understand why you want to do this, anyway, here is the way to achieve it:
#thingy.errors[:base] << "whatever text you want"
In you controller of course.
By the way, the missing template appears to be update, not edit