rails if else check fails then rescue - ruby-on-rails-3

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"

Related

testing PUT update is not working on RSPEC ( Ruby on Rails)

So I'm testing one of my controller in RSPEC and I'm trying to test the whole update shenanigans. This is what i have in the RSPEC
describe 'PUT update' do
before :each do
#user = Factory(:user,name: "Lawrence Smith")
end
context "valid attributes" do
it "located the requested #user" do
put :update, :id => #user, user: Factory.attributes_for(:user)
assigns(:user).should eq(#user)
end
it "changes #user's attributes" do
put :update, :id=> #user.id, user: Factory.attributes_for(:user, name: "Larry Smith")
#user.reload
#user.name.should eq("Larry Smith")
end
end
And this is what i have in the controller
def update
#update and save
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
sign_in #user
format.json{render :json => #user ,:status => :created, :location => #user }
else
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
So apparently the the #user.reload doesn't really refresh the ActiveRecord, as my errors showed that the name has not been changed at all. Any idea what is wrong?
I don't know how you can pass object in get or post parameters. Anyways try like this
describe 'PUT update' do
before :each do
#user = Factory(:user,name: "Lawrence Smith")
end
context "valid attributes" do
it "located the requested #user" do
put :update, :id => #user, user: Factory.attributes_for(:user)
assigns(:user).should eq(#user)
end
it "changes #user's attributes" do
put :update, :id=> #user.id, :user_name => Factory.attributes_for(:user, name: "Larry Smith").name
#user.reload
#user.name.should eq("Larry Smith")
end
end
and this in controller
def update
#update and save
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(:name => params[:user_name])
sign_in #user
format.json{render :json => #user ,:status => :created, :location => #user }
else
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
I think you are getting what I explained here.
Thanks

Rails respond_with behavior for deleted resource?

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

RSpec functional test is redirecting to the wrong place

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

Rails 3 NoMethod Error - undefined method for profile in Profiles#edit with CanCan

In my Rails 3 app, I'm getting redirected to login during my signup process. The steps to signup are supposed to be:
User creates User and Profile
Upon saving user, user is logged into the app and redirected to Profiles#edit (/signup/join)
Upon saving profile, user is redirect to Profiles#show (/profiles/:id)
I'm getting redirected to /login after step 1, and I'm seeing a 302 error after the redirect. If I comment out my before_filter :authenticate in profiles_controller.rb and redo the steps above I don't get redirected out of /signup/join but I get the following error:
NoMethodError in ProfilesController#edit
undefined method `profile' for nil:NilClass
I'm pointed to the first line of my Profiles#edit action:
def edit
#profile = user.profile
if #profile.higher_ed?
higher_ed = HigherEd.find_or_create_by_name(:name => #profile.higher_ed)
end
if #profile.employer?
employer = Employer.find_or_create_by_name(:name => #profile.employer)
end
render :layout => "join_form"
end
I've been making an attempt to implement CanCan in my app, so I thought that was the cause. However I commented out my entire ability.rb file and the problem persists. I'd obviously like to figure out how to fix this without commenting out the before_filter. So if anyone has an idea I'd greatly appreciate it. Since I'm dealing with CanCan which depends on a current_user, I'll start with the definition of current_user in my application_controller.rb:
protected
# Returns the currently logged in user or nil if there isn't one
def current_user
return unless session[:user_id]
#current_user ||= User.find_by_id(session[:user_id])
#current_user ||= User.find_by_auth_token!(cookies[:auth_token]) if cookies[:auth_token]
end
# Make current_user available in templates as a helper
helper_method :current_user
Here's my users_controller.rb:
class UsersController < ApplicationController
before_filter :authenticate, :only => [:edit, :update, :index]
layout "application"
def new
#user = User.new
#user.profile = Profile.new
if logged_in?
redirect_to current_user.profile
end
end
def create
#user = User.new(params[:user])
if #user.save
session[:user_id] = #user.id
redirect_to join_path, :notice => 'User successfully added.'
UserMailer.registration_confirmation(#user).deliver
else
render :action => 'new'
end
end
My profiles_controller.rb:
class ProfilesController < ApplicationController
#before_filter :authenticate, :only => [:edit, :update]
helper_method :find_or_create_group
layout "application", :except => [:edit, :show]
def new
#profile = Profile.new(params[:profile])
end
def create
#profile = Profile.new(params[:profile])
if #profile.save
redirect_to #user.profile, :notice => 'User successfully added.'
else
render :new
end
if #profile.higher_ed?
HigherEd.find_or_create_by_name(:name => #profile.higher_ed)
end
if #profile.employer?
Employer.find_or_create_by_name(:name => #profile.employer)
end
if #profile.job_title?
JobTitle.find_or_create_by_name(:name => #profile.job_title)
end
if #profile.high_school?
HighSchool.find_or_create_by_name(:name => #profile.high_school)
end
end
def user
#user = current_user
end
def edit
#profile = user.profile
if #profile.higher_ed?
higher_ed = HigherEd.find_or_create_by_name(:name => #profile.higher_ed)
end
if #profile.employer?
employer = Employer.find_or_create_by_name(:name => #profile.employer)
end
render :layout => "join_form"
end
My sessions_controller.rb:
class SessionsController < ApplicationController
def new
end
def create
if user = User.authenticate(params[:email].downcase, params[:password])
session[:user_id] = user.id
cookies.permanent[:auth_token] = user.auth_token
if user.profile.higher_ed?
redirect_to user.profile, :notice => "Logged in successfully"
else
redirect_to join_path, :notice => "Logged in successfully"
end
else
flash.now[:alert] = "Invalid login/password. Try again!"
render :action => 'new'
end
end
def destroy
reset_session
cookies.delete(:auth_token)
redirect_to root_path, :notice => "You successfully logged out"
end
end
My ability.rb for CanCan:
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new guest user
if user.role? :admin
can :manage, :all
else
can :manage, :all
end
end
end
My routes.rb:
match "/signup/join" => "profiles#edit", :as => 'join'
#profile = user.profile
Try changing the above line to
#profile = #current_user.profile
or
#profile = current_user.profile
The issue has nothing to do with cancan, rather it has to do with "user" being nil in your controller.
I got it working by reworking my current_user logic. It's now:
def current_user
#current_user ||= lookup_user
end
def lookup_user
if cookies[:auth_token]
User.find_by_auth_token!(cookies[:auth_token])
elsif session[:user_id]
User.find_by_id(session[:user_id])
end
end
That seems to have done the trick.

rspec controller test with devise authentication

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