0

I am trying to test a create action on my users controller. The ask is to allow customers who have previously created accounts, but never actually created a subscription, to use the same email at signup but not be bound to their original password. My test is as follows:

 it "updates the user password for user with no entitlement" do
    user6 = Factory(:user)
    user_params_without_entitlement= { :email => user6.email, :password => "mynewpassword", :password_confirmation => "mynewpassword", publisher_id: user6.publisher_id }

    post :create, user_params_without_entitlement
    hash = Hashie::Mash.new(JSON.parse response.body)
    expect(hash[:errors].present?).to eq(false)
    expect(user6.password).to eq("mynewpassword")
  end

my controller looks like:

def create
if @user.save && @user.activate!
      render :create, status: 200
    elsif @user.errors[:email].first == "Oops! Looks like you've already created an account. Please <a href='/account'>click here to sign in.</a>"
      user = User.find_by_email(params[:email])

      if user.user_entitlements.empty? && user.update_attributes(password: params[:password], password_confirmation: params[:password_confirmation])
        render :create, status: 200
      else
        render json: {errors: @user.errors}, status: 422
      end
    else
      if render json: {errors: @user.errors}, status: 422
      end
    end
end

If I put a binding in below the

user.user_entitlements.empty? && user.update_attributes(password: params[:password], password_confirmation: params[:password_confirmation])

and I call user.password I get "mynewpassword" so the password is updating. in the test though the password is still showing as the original password. I tried adding user6.reload! in the test before the expectation block and I get

NoMethodError: undefined method `reload!' for #<User:0x007fa9a3342fc0>

I found this issue: https://github.com/rweng/pry-rails/issues/9 which suggests that I should modify my .pryrc file. I didn't have a .pryrc file previously. I created a .pryrc file and tried everything in this post(pry gem how to reload?) one at a time with no success. I created the .pryrc in the root of the app and at this point I am at a loss as to what to do.

Community
  • 1
  • 1
ruby_newbie
  • 3,190
  • 3
  • 18
  • 29

3 Answers3

2

it is object.reload to reload an object - without the !bang inside the console you use reload! to reload the hole application models.

so in your case do user6.reload

Tim Kretschmer
  • 2,272
  • 1
  • 22
  • 35
  • while calling user6.reload does not raise an exception it is still showing the old password after calling it. So the test after including that line => Failure/Error: expect(user6.password).to eq('mynewpassword') expected: "mynewpassword" got: "monkey" – ruby_newbie Sep 09 '15 at 16:38
  • well, please go to a console and checkout model.reload and youll see that its reloaded. more i can't help you – Tim Kretschmer Sep 10 '15 at 09:39
1

just to clearout for you, how to use object.reload correctly

User has one profile which has autosave. After_save of profile, the profile is calculating the age and writes that to the user.

[69] pry(main)> a = User.last    
[70] pry(main)> a.age
=> 80

[71] pry(main)> a.profile.birthday = 18.years.ago
[72] pry(main)> a.save
......
  SQL (0.3ms)  UPDATE "users" SET "age" = 18 WHERE "users"."id" = $1  [["id", 6]]
....

[73] pry(main)> a.age
=> 80

[74] pry(main)> a.reload

[75] pry(main)> a.age
=> 18

maybe that clears it out for you. cheers

Tim Kretschmer
  • 2,272
  • 1
  • 22
  • 35
0

Ok so I am not sure if I actually diagnosed the problem but here is my theory on what was happening(I am not going to mark it as the answer until I give you fine folks a chance to debunk my hypothesis).

I think that since the User object doesn't actually have a password attribute(It has crypted_password and salt attributes instead) the data was getting out of sync somehow. I noticed that even when I would find the user by email and call user.password i would get a nil value in the test, but was getting the correct value from a binding in the controller.

I started by posting to the session controller create action with the new password and that worked but felt pretty dirty. I then looked into how the session controller was actually verifying the password and voila, I fixed my test to use the authenticated? method that the session controller was using. Also don't worry I cleaned up the nested if/elses as well. So my test looks like:

context "User without entitlements" do
      let(:user3) { Factory(:user) }
      let(:user_params_without_entitlement) { {:email => user3.email, :password => "mynewpassword", :password_confirmation => "mynewpassword", publisher_id: user3.publisher_id} }

      before do
        post :create, user_params_without_entitlement
      end

      it "updates the user password for user with no entitlement" do

        User.find_by_email(user3.email).authenticated?("mynewpassword").should be_true
      end

      it "returns a 200 if user password is updated" do
        expect(response.code).to eq('200')
      end
    end
ruby_newbie
  • 3,190
  • 3
  • 18
  • 29