Search code examples
ruby-on-railsintegration-testingupdate-attributes

(Rails) update_attributes throws error (needing a password) during integration test that doesn't use password


I'm writing a Rails integration test that checks that the user's title saves. The title has one validation: it has to be no more than 255 characters. But @user.update_attributes!(title: params[:title]) is throwing the error "Password must have at least 6 characters." But...I'm not updating the password or anything other than the title. So how do I save this attribute with its own validation and not worry about the password?

Test:

  test "profile submits new title and description successfully" do
    log_in_as(@non_admin)
    get user_path(@non_admin)
    assert_nil @non_admin.title
    post "/users/#{@non_admin.id}/update_description",
         { title: "I am a man of constant sorrow." }
    user = assigns(:user)
    user.reload.title
    assert user.title == "I am a man of constant sorrow."
    assert_template 'users/show'
    assert flash[:success]
  end

Controller method (not finished, but you'll get the idea). Note, it's the update_attributes! call that throws the password validation error.

  # Handles user's posted title and description.
  def update_description
    @user = User.find(params[:id])
    # Check if title is present. If so, attempt to save, load flash, and reload.
    if @user.update_attributes!(title: params[:title])
      flash[:success] = "Saved title. "
    # if unable, set error flash and reload.
    else
      flash[:warning] = "Unable to save."
    end
    # Same logic as before, now for description.
    # Make sure two different [:success] flashes work! Probably not!
    redirect_to user_path(@user)
  end

Validations:

  validates :password, length: { minimum: 6,
                                 message: "must have at least 6 characters" }
  validates :title, length: { maximum: 255 }

Here's the test error:

23:08:51 - INFO - Running: test/integration/users_show_test.rb
Started
ERROR["test_profile_submits_new_title_and_description_successfully", UsersShowTest, 2017-10-23 01:06:11 -0400]
 test_profile_submits_new_title_and_description_successfully#UsersShowTest (1508735171.57s)
ActiveRecord::RecordInvalid:         ActiveRecord::RecordInvalid: Validation failed: Password must have at least 6 characters
            app/controllers/users_controller.rb:71:in `update_description'
            test/integration/users_show_test.rb:22:in `block in <class:UsersShowTest>'
        app/controllers/users_controller.rb:71:in `update_description'
        test/integration/users_show_test.rb:22:in `block in <class:UsersShowTest>'

In case it's relevant, here's the fixture that is loaded as @non_admin:

archer:
  name: Sterling Archer
  email: [email protected]
  password_digest: <%= User.digest('Jsdfuisd8f') %>
  activated: true
  activated_at: <%= Time.zone.now %>

I'm a Rails noob so it's probably something basic. Thanks in advance...

UPDATE: See discussion with kasperite below. I simply needed to add on: create to my password validation.


Solution

  • Calling update_attributes! will triggers save!, which in turn triggers validation on the model. And since you don't provide password, it will throw the exception.

    You can either do update_attribute(:title, params[:title]) which bypass validation or this:

        @user.title = params[:title]
        @user.save!(validation: false)
    

    See: http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-update-21