After migrate on Rails 3 some RSpec test broken
Example:
Controller:
class ProfilesController < ApplicationController
def create
#profile = Profile.new(params[:note])
respond_to do |format|
if #profile.save
format.html { redirect_to :back }
else
format.html { render :new }
format.js do
render(:update) do |page|
page.flash.show #profile.errors.full_messages.join(', ')
end
end
end
end
end
end
Spec:
require 'spec_helper'
describe ProfilesController do
before(:each) { sign_in mock_model(Account).as_null_object }
context 'POST create' do
it 'is accessible for logged in user' do
controller.should_receive(:create)
post :create
end
end
end
Got failure:
19) ProfilesController POST create is accessible for logged in user
Failure/Error: post :create
ActionView::MissingTemplate:
Missing template profiles/create with {:locale=>[:en, :en], :formats=>[:html], :handlers=>[:rjs, :rhtml, :rxml, :builder, :erb]} in view paths "#<RSpec::Rails::ViewRendering::EmptyTemplatePathSetDecorator:0x1059d48f0>"
# ./spec/controllers/profiles_controller_spec.rb:48
Can you show your controller code?
May be you are really haven't any redirection actions in profiles_controller#create.
something like this:
def create
...
redirect_to '/'
end
Related
post_controller file
class PostsController < ActionController::Base
before_action :authenticate_user!
def index
#post = current_user.posts.paginate(page: params[:page], per_page: 5)
respond_to do |format|
format.html
format.json { render json: #post }
end
end
def new
#post = Post.new
end
def create
#post = current_user.posts.build(post_param)
if #post.save
redirect_to action: 'index'
else
render 'new'
end
post_controller_test
require 'test_helper'
class PostsControllerTest < ActionController::TestCase
include Devise::TestHelpers
def setup
#user = users(:Bob)
#post = Post.new
end #passed
test 'logged in should get show' do
sign_in #user
get :index
assert_response :success
end #passed
test 'not authenticated should get redirect' do
get :index
assert_response :redirect
end #passed
test 'should get index' do
get :index
assert_response :success
assert_not_nil assigns(:posts)
end #failing
test "should destroy post" do
assert_difference('Post.count', -1) do
delete :destroy, id: #post
end
assert_redirected_to posts_path
end #failing
...
devise is setup and working fine but why I am getting 302 error in last two cases. Is it because I am not passing #user parameters to it? I did but it was still throwing the same error. I also checked out my routes file which is fine because post_controller is working fine in development mode.
What I am doing wrong here?
Edit-1
I tried to create test cases for create method
def setup
#user = users(:bob)
#p = posts(:one)
#post = Post.new
end
test 'should create post' do
sign_in #user
assert_difference('Post.count') do
post :create, post: { name: #p.name, value: #p.value}
end
end
I am getting ActionController::ParameterMissing: param is missing or the value is empty: post while in my controller class I do have
params.require(:post).permit(:name, :value, :user_id)
I also have all parameters in my .yml file i.e.
one:
name: 2
value: 3
It looks like you need to sign in before trying the index action. You're also testing the wrong instance variable name. You're testing #posts, but you've defined #post in the controller. Try this test instead:
test 'should get index' do
sign_in #user
get :index
assert_response :success
assert_not_nil assigns(:post)
end
An integration test is returning a 'Missing Template' error. The microposts_interface_test.rb errors on /members. It may be because the /members view uses the MicropostsController but I'm unsure how to fix the test.
ERROR["test_micropost_interface", MicropostsInterfaceTest, 2015-06-19 06:40:32 +0800]
test_micropost_interface#MicropostsInterfaceTest (1434667232.75s)
ActionView::MissingTemplate: ActionView::MissingTemplate: Missing template /members with {:locale=>[:en], :formats=>[:html], :variants=>[], :handlers=>[:erb, :builder, :raw, :ruby, :coffee, :haml, :jbuilder]}. Searched in:
* "/home/me/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/web-console-2.0.0.beta3/lib/action_dispatch/templates"
* "/home/me/Development/my_app/app/views"
* "/home/me/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/web-console-2.0.0.beta3/app/views"
* "/home/me/.rbenv/versions/2.2.1/lib/ruby/gems/2.2.0/gems/phrasing-4.0.0rc9/app/views"
app/controllers/microposts_controller.rb:14:in `create'
test/integration/microposts_interface_test.rb:16:in `block (2 levels) in <class:MicropostsInterfaceTest>'
test/integration/microposts_interface_test.rb:15:in `block in <class:MicropostsInterfaceTest>'
app/controllers/microposts_controller.rb:14:in `create'
test/integration/microposts_interface_test.rb:16:in `block (2 levels) in <class:MicropostsInterfaceTest>'
test/integration/microposts_interface_test.rb:15:in `block in <class:MicropostsInterfaceTest>'
MicropostsInterfaceTest:
require 'test_helper'
class MicropostsInterfaceTest < ActionDispatch::IntegrationTest
def setup
#user = users(:michael)
end
test "micropost interface" do
log_in_as(#user)
get members_path
assert_select 'div.pagination'
assert_select 'input[type=file]'
# Invalid submission
assert_no_difference 'Micropost.count' do
post microposts_path, micropost: { content: "" }
end
assert_select 'div#error_explanation'
# Valid submission
content = "This micropost really ties the room together"
picture = fixture_file_upload('test/fixtures/rails.png', 'image/png')
assert_difference 'Micropost.count', 1 do
post microposts_path, micropost: { content: content, picture: picture }
end
assert assigns(:micropost).picture?
assert_redirected_to root_url
follow_redirect!
assert_match content, response.body
# Delete a post.
assert_select 'a', text: 'delete'
first_micropost = #user.microposts.paginate(page: 1).first
assert_difference 'Micropost.count', -1 do
delete micropost_path(first_micropost)
end
# Visit a different user.
get user_path(users(:archer))
assert_select 'a', text: 'delete', count: 0
end
test "micropost sidebar count" do
log_in_as(#user)
get members_path
assert_match "#{#user.microposts.count} microposts", response.body
# User with zero microposts
other_user = users(:mallory)
log_in_as(other_user)
get members_path
assert_match "0 microposts", response.body
# Create a micropost.
other_user.microposts.create!(content: "A micropost")
get members_path
assert_match "1 micropost", response.body
end
end
Update:
# controller/members_controller.rb
class MembersController < ApplicationController
before_filter :logged_in_user
def index
#micropost = current_user.microposts.build
#feed_items = current_user.feed.paginate(page: params[:page])
end
end
I confirm there is a specific index view at app/views/members/index.html.erb.
Update 2:
# controller/microposts_controller.rb
class MicropostsController < ApplicationController
before_action :logged_in_user, only: [:create, :destroy]
before_action :correct_user, only: :destroy
def create
#micropost = current_user.microposts.build(micropost_params)
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to members_path
else
#feed_items = []
render members_path
end
end
def destroy
#micropost.destroy
flash[:success] = "Micropost deleted"
redirect_to request.referrer || members_path
end
private
def micropost_params
params.require(:micropost).permit(:content, :picture)
end
def correct_user
#micropost = current_user.microposts.find_by(id: params[:id])
redirect_to members_path if #micropost.nil?
end
end
In the create action in the MicropostController use render "members/index" instead of render members_path. Note that render does not load the variables needed in members/index, it only loads the template so add #micropost = [] just like you did for #feed_items = [] so that if you are calling those variables from the view you don't get an error of can't find variable #microposts. Or you can simply redirect_to members_path.
It was useful for me:
render template: 'template', formats: [:html]
So I'm testing out a very simple API in Rails to see if I can create a user from it locally using the Chrome plugin Postman (REST Client extension).
In my rails app, I've set up a folder/namespace for my API, and whenever I try to create my user, I get the following error:
Missing template api/v1/users/create, application/create with {:locale=>[:en], :formats=>[:json], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder, :coffee]}. Searched in: * "PATH/app/views"
I'm using Rails 4.0.1 and Ruby 2.0
I'm posting a screenshot below of what I'm posting:
module Api
module V1
class UsersController < ApplicationController
class User < ::User
# add any hacks
end
respond_to :json
def index
respond_with User.all
end
def show
respond_with User.find(params[:id])
end
def new
#user = User.new
end
def create
#user = User.create(user_params)
# respond_with(#user)
if #user.save
# render json: #user, status: :created, location: #user
redirect_to #user
end
end
private
def user_params
params.require(:user).permit(:name, :age, :location) if params[:user]
end
end
end
end
So based on my user_params, I should be able to create a new user, correct?
Please let me know if you need any additional info and I'll do my best to respond ASAP!
Thanks!
You can create user using API.
1) First you need to put proper resources in your routes.rb:
YourApp::Application.routes.draw do
namespace :api do
namespace :v1 do
resources :users
end
namespace :v2 do
# ... if needed
end
end
root to: 'users#index'
end
2) You need to create a RESTfull-style controller to process requests. Here how your action 'create' may be implemented.
def create
respond_with User.create(fio: params[:fio], phone: params[:phone], region: params[:region], updated_at: Time.now)
end
Example of 'create' with respond_to:
def create
# ...
respond_to do |format|
format.html {render text: "Your data was sucessfully loaded. Thanks"}
format.json {
User.create(... params ...)
render text: User.last.to_json # !
}
end
end
See documents about respond_with and respond_to if you need something special to respond.
Also can be helpful railscasts episodes about API building: #350 and #352
P.S. folder/namespace/v1/users_controller shall be the same as class name in your module Api
P.S.2 You can observe my app, where you can probably find something helpful (same as your app - simple API for records creating) - myApp
Example of users_controller (controllers/api/v1/users_controller.rb):
#encoding: utf-8
module Api
module V1
class UsersController < ApplicationController # Api::BaseController
before_filter :authenticate_user!, except: [:create, :index]
respond_to :json
def index
#respond_with
respond_to do |format|
format.html {render text: "Your data was sucessfully loaded. Thanks"}
format.json { render text: User.last.to_json }
end
end
def show
respond_with User.find(params[:id])
end
def create
respond_with User.create(access_token: params[:access_token], city: params[:city], created_at: Time.now, phone: params[:phone], region: params[:region], updated_at: Time.now)
end
def update
respond_with User.update(params[:id], params[:users])
end
def destroy
respond_with User.destroy(params[:id])
end
end
end
end
redirect dose not return, so your create method will keep looking for template to render, and then find there is no matching template.
To fix, you need to explicitly return redirect
if #user.save
return redirect_to(#user)
end
You also need to pay attention to the default url of #user. It's better to assign a named path explicitly in this case, say redirect_to(user_path(#user))
Trying to write what should be a straightforward RSpec test and have set up my create action to render JSON like the following:
require 'spec_helper'
describe CommentsController do
let(:valid_attributes) do
{
title: 'First Comment', comment_text: 'LoremIpsum', commentable_id: 1,
user_id: 1, entered_by: 'john', last_updated_by: 'doe'
}
end
context 'JSON' do
describe 'POST create' do
describe 'with valid params' do
it 'creates a new Comment' do
json = {:format => 'json', :comment => valid_attributes}
post :create, json
end
it 'assigns a newly created comment as #comment' do
json = {:format => 'json', :comment => valid_attributes}
post :create, json
assigns(:comment).should be_a(Comment)
assigns(:comment).should be_persisted
end
end
end
end
end
However I am getting the following output:
ActionView::MissingTemplate: Missing template comments/create, application/create with {:locale=>[:en], :formats=>[:json], :handlers=>[:erb, :builder, :raw, :ruby, :jbuilder, :coffee, :haml]}. Searched in:
you missed the else part when #commentable is nil. this will try rendering the default template!
to clarify:
this is what was posted initially:
def create
if #commentable
#comment = #commentable.comments.new(comment_params)
if #comment.save
render json: #comment, status: :created
else
render json: #comment.errors, status: :unprocessable_entity
end
end
end
in the case where #commentable is nil there is nothing that tells rails what to render, so it will try to render the default template for the create action. this is where Missing template comments/create comes from.
what i mean with the else part is this:
def create
if #commentable
[...]
else
head 404
end
end
I'm learning how to register a user using forms on Rails and followed Rails Rutotrial by typing in:
class UsersController < ApplicationController
def create
#user = User.new(params[:user])
if #user.save
# Handle a successful save.
else
#title = "Sign up"
render 'new'
end
end
end
BUT, that gave me the following error:
Missing template users/create, application/create with {:handlers=>[:erb, :builder, :coffee], :formats=>[:html], :locale=>[:en, :en]}
Note sure why, but when I fixed my code to:
class UsersController < ApplicationController
def create
#user = User.new(params[:user])
if #user.save
# Handle a successful save.
else
#title = "Sign up"
render :action => 'new'
end
end
end
this worked. I'm new to Rails and don't understand why. I put up this post in case there were others out there similarly struggling. But any explanation regarding what's going on would be very much welcome.
You should only be getting that error if your #user.save is successful. From your code, what is essentially is happening is
if #user.save
# Handle a successful save
else
#title = "Sign up"
render 'new'
end
render 'create'
because if you don't tell it to render anything, it will render views/users/create.html.erb (aka /views/{controller}/{action}.html.erb) and it appears that views/users/create.html.erb doesn't exist (note that if you are using HAML, it would be views/users/create.html.haml). Maybe you are looking for something like
if #user.save
redirect_to root_path and return
end
#title = "Sign up"
render 'new'
That way, if #user.save fails to save, it will always render the new template, otherwise redirect elsewhere.