I'm using respond_to and respond_with pair in Rails 3 to respond to a DELETE #destroy request. The destroy action is defined in UsersController. It destroy the User specified by params[:id] and respond with a JS template. However, the request keeps failing in RSpec test and I'm not really sure how to fix it.
Here's a snippet for my UsersController:
class UsersController < ApplicationController
respond_to :html, only: [:index, :show, :new, :edit]
respond_to :js, only: [:create, :update, :delete]
...
def destroy
#user = User.find(params[:id])
#user.destroy
respond_with #user
end
end
And here is the test that keeps failing:
require 'spec_helper'
describe UsersController do
...
describe "DELETE #destroy" do
before { #user = create(:user); delete :destroy, id: #user.id, format: :js }
it "return HTTP success" do
response.should be_success
end
it "respond with JS content" do
response.content_type.should == 'text/javascript'
end
end
end
The test "respond with JS content" does succeed, however the test "return HTTP successs" fails. When I use a debugger to check response.code, it is 406. I'm expecting 2xx since the deletion succeed. Is this a normal Rails behavior or do I have something wrong with my code?
Seems you messed up REST delete and controller's destroy. Rails responder knows nothing about :delete action, change
respond_to :js, only: [:create, :update, :delete]
to
respond_to :js, only: [:create, :update, :destroy]
or pass a block to the responder, instead of
respond_with #user
use
respond_with #user do |format|
format.js
end
Related
I'm using rails 5.1.4 , so I have a table USER within I store all the users, then a user can send friend request to other users, and I want to store that request into other table named FRIEND, like user_1 ( who send the request) - user_2 (who is requested for) , but you will understand that those two user (user_1, user_2) are coming from USER table.
It means: first I have this table Users which contains all the users. And what I want to say is that any user in this table user can be friend with any other user from the same table user.
I'm not 100% certain what your asking in your question but it sounds like what you're looking to do is to have a table called Users and another table called Friends and to be able to store a value for the friend request. I believe what you want to look into is a "has_many :through association" using a "join table". Check out this video it walks you through it http://blog.teamtreehouse.com/what-is-a-has_many-through-association-in-ruby-on-rails-treehouse-quick-tip
here's more info on the Active Record association http://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
EDIT:
Based on your below post what you want to do is just a simple has_many association. In your User model add has_many :friends, dependent: :destroy and in your Friend model add belongs_to :users now go to your routes file and make friends a nested route of user by doing
# nested routes for users
resources :users do
resources :friends
end
in your friends table make sure you add a foreign key for users lik ethis in the migration t.references :user, foreign_key: true
now in your friends_controller you need to update the actions like this. Replace the example "patent" with your "friend" object.
class PatentsController < ApplicationController
# first loads #user and then #patent for the below actions.
before_action :set_user, only: [:index, :show, :new, :edit, :create, :update]
before_action :set_patent, only: [:show, :edit, :update, :destroy]
# GET /patents
# GET /patents.json
def index
#patents = #user.patents
end
# GET /patents/1
# GET /patents/1.json
def show
end
# GET /patents/new
def new
#patent = #user.patents.new
end
# GET /patents/1/edit
def edit
end
# POST /patents
# POST /patents.json
def create
#patent = #user.patents.new(patent_params)
respond_to do |format|
if #patent.save
format.html { redirect_to user_patents_path(#patent.user), notice: 'Patent was successfully created.' }
format.json { render :show, status: :created, location: #patent }
else
format.html { render :new }
format.json { render json: #patent.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /patents/1
# PATCH/PUT /patents/1.json
def update
respond_to do |format|
if #patent.update(patent_params)
format.html { redirect_to user_patents_path(#patent.user), notice: 'Patent was successfully updated.' }
format.json { render :show, status: :ok, location: #patent }
else
format.html { render :edit }
format.json { render json: #patent.errors, status: :unprocessable_entity }
end
end
end
# DELETE /patents/1
# DELETE /patents/1.json
def destroy
#patent.destroy
respond_to do |format|
format.html { redirect_to user_url(#user), notice: 'Patent was successfully destroyed.' }
format.json { head :no_content }
end
end
#######################
# private methods
#######################
private
# Use callbacks to share common setup or constraints between actions.
def set_user
#user = User.find(params[:user_id])
end
def set_patent
#patent = Patent.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def patent_params
params.require(:patent).permit(:patent_title, :patent_office, :patent_number, :patent_status, :patent_date, :patent_description, :user_id)
end
end
I have 2 methods in my controller for finding the user (notice the enabled_only scope):
before_filter :find_user, :only => :show
before_filter :find_any_user, :only => [:edit, :update, :destroy]
def find_user
#user = User.enabled_only.find(params[:id])
rescue ActiveRecord::RecordNotFound
flash[:alert] = "The user you were looking for could not be found"
redirect_to root_path
end
def find_any_user
#user = User.find(params[:id])
rescue ActiveRecord::RecordNotFound
flash[:alert] = "The user you were looking for could not be found"
redirect_to root_path
end
Surely these could be merged into one method that checks whether :action == 'show' but I couldn't get the rescue to catch the error. I tried something like the following but it didn't work:
before_filter :find_user, :only => [:show, :edit, :update, :destroy]
def find_user
#user = if :action == 'show'
User.enabled_only.find(params[:id])
else
User.find(params[:id])
end
rescue ActiveRecord::RecordNotFound
flash[:alert] = "The user you were looking for could not be found"
redirect_to root_path
end
Please advise on how this can be done.
Thanks
You need to wrap the code you want to 'protect' between a beginand a rescue
before_filter :find_user, :only => [:show, :edit, :update, :destroy]
def find_user
begin
#user = if :action == 'show'
User.enabled_only.find(params[:id])
else
User.find(params[:id])
end
rescue ActiveRecord::RecordNotFound
flash[:alert] = "The user you were looking for could not be found"
redirect_to root_path
end
end
and by the way your test :action == 'show' can never be true. :action is a symbol which value is :action, its value will never change, same for 'show', its value will never change. I'm not sure what's the best way to achieve this but you could do but you could do if params[:action] == "show"
I need some help guys, trying to make this test to pass but with no luck.
describe 'PUT posts/:id' do
describe 'with valid attributes' do
let(:mock_post) { mock_model('Post', title: 'hey! iam a mock!', description: 'a sexy model', location: 'everywhere') }
login_user
it 'should update the object and redirect to the post' do
Post.stub!(:find).with(mock_post.id).and_return(mock_post)
Post.any_instance.should_receive(:update_attributes).with({"these" => "params"}).and_return(true)
response.should redirect_to post_path(mock_post)
put :update, id: mock_post.id, post: { these: 'params' }
end
it 'should have a current_user' do
subject.current_user.should_not be_nil
end
end
For now, I have something like the above test and getting the following error:
1) PostsController PUT posts/:id with valid attributes should update the object and redirect to the post
Failure/Error: response.should redirect_to post_path(mock_post)
Expected response to be a <:redirect>, but was <200>
# ./spec/controllers/posts_controller_spec.rb:200:in `block (4 levels) in <top (required)>'
PostsController:
class PostsController < ApplicationController
load_and_authorize_resource except: [:index, :show]
before_filter :authenticate_user!, except: [:index, :show, :tags]
before_filter :find_post, only: [:show, :edit, :update, :suspend, :suspend_alert]
def update
if #post.update_attributes(params[:post])
flash[:success] = 'Cool.'
redirect_to post_path(#post)
else
render :edit
end
end
protected
def find_post
#post = Post.find(params[:id])
end
end
Also, how should I write the test for the render :edit part?
Your spec never calls the controller action. Try adding:
Post.any_instance.
should_receive(:update_attributes).
with({"these" => "params"})
put :update, :id => "1", :post => {"these" => "params"}
To test the two paths that result from the call to update_attributes, substitute the value in the expectation:
it "should redirect when successful" do
Post.any_instance.
should_receive(:update_attributes).
with({"these" => "params"}).
and_return(true)`
response.should_redirect_to(post_path(#mock_post))
put :update, :id => "1", :post => {"these" => "params"}
end
it "should render the edit page when unsuccessful" do
Post.any_instance.
should_receive(:update_attributes).
with({"these" => "params"}).
and_return(false)`
response.should render_template("edit")
put :update, :id => "1", :post => {"these" => "params"}
end
I am having problem with rspec testing controller the devise authentication.
I have a following setup
I have included
config.include Devise::TestHelpers, :type => :controller
in my spec_helper.rb
In my merchants_controller_spec.rb
describe MerchantsController do
before :each do
#user = Factory(:user)
#merchant = Factory(:merchant, :user_id => #user.id,:is_approved => false, :is_blacklisted => false)
controller.stub!(:current_user).and_return(#user)
end
describe "GET index" do
it "assigns all merchants as #merchants" do
merchant = Factory(:merchant,:is_approved => true, :is_blacklisted => false)
get :index
assigns(:merchants).should eq([merchant])
end
end
end
My merchants_controller.rb
class MerchantsController < ApplicationController
before_filter :authenticate_user!
def index
#merchants = Merchant.approved
debugger
respond_to do |format|
format.html # index.html.erb
format.xml { render :xml => #merchants }
end
end
end
I have a scope approved in merchant model
scope :approved, where(:is_approved => true, :is_blacklisted => false)
Now my problem is even though i stubbed current_user and returned #user as current_user, My merchants_controller index spec is failing. But if i comment out authenticate_user! then the spec passes,
without authenticate_user! the debugger of index action is caught but with authenticate_user! debugger is not caught.
I think there is problem in subbing current_user and i am not able to figure it out.
Help me out..
Have you read through the docs on github?:
Devise includes some tests helpers for functional specs. To use them, you just need to include Devise::TestHelpers in your test class and use the sign_in and sign_out methods. Such methods have the same signature as in controllers:
sign_in :user, #user # sign_in(scope, resource)
sign_in #user # sign_in(resource)
sign_out :user # sign_out(scope)
sign_out #user # sign_out(resource)
Another alternative
RSpec.describe YourController, :type => :controller do
before do
user = FactoryGirl.create(:user)
allow(controller).to receive(:authenticate_user!).and_return(true)
allow(controller).to receive(:current_user).and_return(user)
end
# rest of the code
end
I have the following in my controller:
respond_to :html, :except => :some_action
respond_to :json, :xml
If you hit the :some_action route in a browser (tested with Chrome), you get a 406 Not Acceptable response back. Is there a way to "catch" this in Rails and do something else (like a redirect)?
Additionally, I'm trying to avoid using the block form of respond_to. I'm just curious if there is some way to handle this case.
Check this out: http://ryandaigle.com/articles/2009/8/6/what-s-new-in-edge-rails-cleaner-restful-controllers-w-respond_with
There's a bit about action overriding:
class UsersController < ApplicationController::Base
respond_to :html, :xml, :json
# Override html format since we want to redirect to a different page,
# not just serve back the new resource
def create
#user = User.create(params[:user])
respond_with(#user) do |format|
format.html { redirect_to users_path }
end
end
end