Rails: password can't be blank, BCrypt - ruby-on-rails

I have a user model
class User < ApplicationRecord
include ApplicationConstants
enum role: { admin: 0, waiter: 1, chef:2 }
has_secure_password
validates :name, :role, presence: true, on: :create
validates :email, uniqueness: true, format: EMAIL_REGEX
validates :password, length: { minimum: 8 }, allow_blank: true
end
The controller definition is:
before_action :set_user, only: [:show, :update, :destroy]
def update
if #user.update(user_params)
render json: #user
else
render json: #user.errors, status: :unprocessable_entity
end
end
def set_user
#user = User.find(params[:id])
end
def user_params
params.permit(:name, :role, :email, :password, :password_confirmation)
end
The problem is the following test case fails
test "should update user" do
put user_url(#user), params: { name: #user.name }
assert_response 200
end
The error is: {"password":["can't be blank"]}
I tried other answers like the one listed here, but it didn't work

As Matt pointed out, it was because of the digest attribute being nil. I added it to the fixtures and now it works.

Related

"password_digest can't be blank" and "password can't be blank" errors

I'm trying to create a user via Postman as shown in the screenshot, but getting errors:
This is a rails app created with an --api option.
user.rb
class User < ApplicationRecord
validates :email, uniqueness: true
validates_format_of :email, with: /#/
validates :password_digest, presence: true
has_secure_password
end
users_controller.rb
class Api::V1::UsersController < ApplicationController
# GET /users/1
def show
render json: User.find(params[:id])
end
# POST /users
def create
#user = User.new(user_params)
if #user.save
render json: #user, status: :created
else
render json: #user.errors, status: :unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:email, :password)
end
end
routes.rb
Rails.application.routes.draw do
namespace :api, defaults: { format: :json } do
namespace :v1 do
resources :users, only: [:show, :create]
end
end
end
Your user_params method expects the attributes nested in a user hash. Change the response to:
{
"user": {
"email": "...",
"password": "..."
}
}
Btw the validates :password_digest, presence: true line is not needed because has_secure_password has validations build in and ensures internally that a password is present.

ROR 5 API - Internal Server Error when doing a POST action

Im trying to resolve this many days ago. I really don't know how to fix this issue. Im just a beginner with rails and im creating an api for personal use. here's my code:
users_controller.rb:
class UsersController < ApplicationController
def index
users = orchestrate_query(User.all)
render serialize(users)
end
def show
render serialize(user)
end
def create
user = User.new(user_params)
if user.save
UserMailer.confirmation_email(user).deliver_now
render serialize(user).merge(status: :created, location: user)
else
unprocessable_entity!(user)
end
end
def update
user = User.find(params[:id])
if user.update(user_params)
render serialize(user).merge(status: :ok)
else
unprocessable_entity!(user)
end
end
def destroy
user.destroy
render status: :no_content
end
private
def user
#user ||= params[:id] ? User.find_by!(id: params[:id]) : User.new(user_params)
end
alias_method :resource, :user
def user_params
params.require(:data).permit(:email, :password, :given_name, :family_name, :role, :confirmation_redirect_url)
end
end
users_confirmation_controller.rb:
class UserConfirmationsController < ActionController::API
before_action :confirmation_token_not_found
def show
user.confirm
if user.confirmation_redirect_url
redirect_to(user.confirmation_redirect_url)
else
render plain: 'You are now confirmed!'
end
end
private
def confirmation_token_not_found
render(status: 404, plain: 'Token not found') unless user
end
def confirmation_token
#confirmation_token ||= params[:confirmation_token]
end
def user
#user ||= User.where(confirmation_token: confirmation_token).first
end
end
user.rb -> model
class User < ApplicationRecord
has_secure_password
before_validation :generate_confirmation_token, on: :create
before_validation :downcase_email
enum role: [:user, :admin]
validates :email, presence: true,
uniqueness: true,
length: { maximum: 255 },
format: { with: /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i }
validates :password, presence: true, length: { minimum: 8 }, if: :new_record?
validates :given_name, length: { maximum: 100 }
validates :family_name, length: { maximum: 100 }
validates :confirmation_token, presence: true, uniqueness: { case_sensitive: true }
def confirm
update_columns({
confirmation_token: nil,
confirmed_at: Time.now
})
end
private
def generate_confirmation_token
self.confirmation_token = SecureRandom.hex
end
def downcase_email
email.downcase! if email
end
end
user_presenter.rb
class UserPresenter < BasePresenter
FIELDS = [:id, :email, :given_name, :family_name, :role, :last_logged_in_at,
:confirmed_at, :confirmation_sent_at, :reset_password_sent_at,
:created_at, :updated_at]
sort_by *FIELDS
filter_by *FIELDS
build_with *[FIELDS.push([:confirmation_token, :reset_password_token,
:confirmation_redirect_url,
:reset_password_redirect_url])].flatten
end
routes.rb
Rails.application.routes.draw do
scope :api do
resources :resorts, except: :put
resources :contact_info, except: :put
resources :users, except: :put
resources :user_confirmations, only: :show, param: :confirmation_token
get '/search/:text', to: 'search#index'
end
root to: 'resorts#index'
end
this is my request to my REST Client;
Method: POST, URL: http://localhost:3000/api/users;
Headers: application/json; and body is:
{"data":{"email":"john#gmail.com",
"password": "password",
"confirmation_redirect_url":"http://google.com"}}
Here is the error:
"error": "Internal Server Error",
app/controllers/users_controller.rb:12:in `create'
please help me. im stuck with it for the past 3 days now.
app/controllers/users_controller.rb:12:in `create'
You need to add an attribute to your users table password_digest:string when using has_secure_password. I am not positive on why your errors aren't showing correctly but this should fix the problem.
http://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html
has_secure_password
short definition
Adds methods to set and authenticate against a BCrypt password. This mechanism requires you to have a password_digest attribute.
Your user params require you to call the User model to access and save the attributes YOU defined in the User table
def user_params
params.require(:user).permit(:email, :password, :given_name, :family_name, :role, :confirmation_redirect_url)
end

updating resource undefined method `valid?' for false:FalseClass

I have some validations for my Lesson model, and I'm able to highlight validation problems on the controller under the create action with the valid? method. However, if I try to valid? in an analogous manner, I get undefined methodvalid?' for false:FalseClass` How can I go about validating my edit form upon submission, such that it renders the edit form again if the validation doesn't pass?
Lesson model:
class Lesson < ActiveRecord::Base
belongs_to :user
has_many :words, dependent: :destroy
validates :title, presence: true, length: { maximum: 55 }
validates :description, presence: true, length: { maximum: 500 }
validates :subject, presence: true, length: { maximum: 55 }
validates :difficulty, presence: true, numericality: { less_than_or_equal_to: 5 }
end
Controller:
class Teacher::LessonsController < ApplicationController
before_action :authenticate_user!
before_action :require_authorized_for_current_lesson, only: [:show, :edit, :update]
def show
#lesson = Lesson.find(params[:id])
end
def new
#lesson = Lesson.new
end
def edit
#lesson = Lesson.find(params[:id])
end
def create
#lesson = current_user.lessons.create(lesson_params)
if #lesson.valid?
redirect_to teacher_lesson_path(#lesson)
else
render :new, status: :unprocessable_entity
end
end
def update
#lesson = current_lesson.update_attributes(lesson_params)
if #lesson.valid?
redirect_to teacher_lesson_path(current_lesson)
else
render :edit, status: :unprocessable_entity
end
end
private
def require_authorized_for_current_lesson
if current_lesson.user != current_user
render text: "Unauthorized", status: :unauthorized
end
end
def current_lesson
#current_lesson ||= Lesson.find(params[:id])
end
def lesson_params
params.require(:lesson).permit(:title, :description, :subject, :difficulty)
end
end
If you see an error that looks like undefined method 'valid?' for 'false:FalseClass
That means that wherever you call the method :valid?, the object on which you are calling it is not the object you expect, it is instead just false
So you have two instances in your code where you are calling #lesson.valid?, which means one or both of the assignments of #lesson is sometimes returning false.
In the docs of create, it says: The resulting object is returned whether the object was saved successfully to the database or not.
In the docs of update_attributes, it says: If the object is invalid, the saving will fail and false will be returned.
So it looks like your problem is with update_attributes, which apparently just returns false if your update was unsuccessful.

Rails 4 'permit' and 'count by one' errors

I'm in the process of learning Rails by following Agile Web Development with Rails 4. I am at chapter 9, just finnished unit testing. In order to better apprehend what I'm reading, I am building step by step my own application, along with the one I have to build following the book. The book goes through building an e-shop, my application is a patients record keeping application.
I am in the process of writing tests. I generated two scaffolds Doctors and Patients. For Patients everything went fine as it should be, since I'm actually doing everything in a parallel way with the book.
For Doctors though, I had a problem where [params] in the app/controller/doctors_controller.rb where the payload was passed as String instead of a Hash. More specifically, the error I get is:
DoctorsControllerTest
ERROR (0:00:00.094) test_should_create_doctor
undefined method `permit' for "625417172":String
# app/controllers/doctors_controller.rb:72:in `doctor_params'
app/controllers/doctors_controller.rb:27:in `create'
[...]
I double checked the code and everything is similar to Patients controller, but I have no problems there! After doing some online research I managed to bypass this error using attributes:
[...]
test "should create doctor" do
assert_difference('Doctor.count') do
post :create, doctor: #doctor.attributes # instead of #doctor
end
assert_redirected_to doctor_path(assigns(:doctor))
end
[...]
But then when I run the rake test I the following error:
DoctorsControllerTest
FAIL (0:00:00.182) test_should_create_doctor
"Doctor.count" didn't change by 1.
Expected: 3
Actual: 2
I'd be glad if someone could give me some hints on how to get PASS this test by adressing possibly the 1st reported error - which in IMHO it's the real source of my problems - or at least the second one so I can continue my project.
EDIT: Sharing requested code:
My model for Doctor is:
class Doctor < ActiveRecord::Base
validates :name, presence: {message: "Συμπληρώστε το όνομα του ιατρού"}
validates :surname, presence: {message: "Συμπληρώστε το επώνυμο του ιατρού"}
validates :birthday, presence: {message: "Συμπληρώστε την ημερομηνία γεννήσεως ιατρού"}
validates :gender, presence: {message: "Συμπληρώστε το γένος του ιατρού"}
validates :identity_number, presence: {message: "Συμπληρώστε τον αριθρμό αστυνομικής ταυτότητας του ιατρού"}
validates :identity_number_pd, presence: {message: "Συμπληρώστε την πόλη του αστυνομικού τμήματος που εξέδωσε την ταυτότητα"}
validates :father_name, presence: {message: "Συμπληρώστε το πατρώνμου ιατρού"}
validates :doctor_specialty, presence: {message: "Συμπληρώστε την ειδικότητα του ιατρού"}
validates :doc_medical_association_city, presence: {message: "Συμπληρώστε την πόλη του ιατρικού συλλόγου που είναι εγγεγραμένος ο ιατρός"}
validates :home_phone, presence: {message: "Συμπληρώστε τον αριθμό τηλεφώνου οικίας του ιατρού"}
validates :mobile_phone, presence: {message: "Συμπληρώστε το κινητό τηλέφωνο του ιατρού"}
validates :city, presence: {message: "Συμπληρώστε την πόλη κατοικίας του ιατρού"}
validates :country, presence: {message: "Συμπληρώστε χώρα της κατοικίας του ιατρού"}
validates :postal_code, presence: {message: "Συμπληρώστε τον ταχυδρομικό κώδικα της οικίας του ιατρού"}
validates :image_url, allow_blank: true, format: {
with: %r{\.(gif|jpg|png)\Z}i, message: "Η μορφή της φωτογραφίας πρέπει να είναι PNG, JPG ή GIF"
}
validates :email, :allow_blank => true,:uniqueness => { :case_sensitive => false }, :email_format => {:message => 'Η διεύθυνση email που έχετε εισαγάγει είναι λανθασμένη'}
# Εξωτερικές συναρτήσεις (methods) για validation
validate :birthday_is_date # γεννέθλια
validate :doc_medical_association_no_check
# Έλεγχος ορθότητας ημερομηνίας γεννήσεως. Στην βάση δεδομένων η ημερομηνίες θα σωθούν με το Αμερικάνικο σύστημα
# πιο συγκεκριμένα: Χρονιά/μήνα/ημέρα, π.χ. 1972/11/24
def birthday_is_date
errors.add(:birthday, "Λάθος στην ημερομηνία γεννήσεως!") unless Chronic.parse(birthday)
end
# Έλεγχος για μοναδικό άριθμο μητρώου ιατρού. Εδώ το validation μπορεί να δημιουργήσει πρόβλημα. Πρέπει να εισαχθεί και τρίτο 'condition' - 14/03/14
def doc_medical_association_no_check
if doc_medical_association_no
errors.add(:doc_medical_association_no, "Ο αριθμός μητρώου υπάρχει είδη στην βάση δεδομένων!") if Doctor.exists?(["doc_medical_association_no = ? and not surname = ?", self.doc_medical_association_no, self.surname])
end
end
end
Test controller for Doctor is:
require 'test_helper'
class DoctorsControllerTest < ActionController::TestCase
setup do
#doctor = doctors(:alex)
#update = {
name: "Απόστολος",
surname: "Παπαδόπουλος",
gender: "Άνδρας",
birthday: Date.parse('1981-08-01'),
identity_number: "ΑT12314",
identity_number_pd: "Ξάνθης",
image_url: "ap_pap.jpg",
father_name: "Στέλιος",
doctor_specialty: "Πνευμονολόγος",
doc_medical_association_city: "ΑΘήνα",
doc_medical_association_no: "12345",
home_phone: "+30 1234567",
mobile_phone: "+30 1234567",
home_address: "Τεστ 32",
city: "Αθήνα",
country: "Ελλάδα",
postal_code: "12345",
email: "papa#somemail.com"
}
end
test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:doctors)
end
test "should get new" do
get :new
assert_response :success
end
test "should create doctor" do
assert_difference('Doctor.count') do
post :create, doctor: #doctor # or #doctor.attributes but with the 'count by 1' error
end
assert_redirected_to doctor_path(assigns(:doctor))
end
test "should show doctor" do
get :show, id: #doctor
assert_response :success
end
test "should get edit" do
get :edit, id: #doctor
assert_response :success
end
test "should update doctor" do
patch :update, id: #doctor, doctor: #update
assert_redirected_to doctor_path(assigns(:doctor))
end
test "should destroy doctor" do
assert_difference('Doctor.count', -1) do
delete :destroy, id: #doctor
end
assert_redirected_to doctors_path
end
end
Of course doctor(:alex) is my fixture.
And finally controller for Doctor is:
class DoctorsController < ApplicationController
before_action :set_doctor, only: [:show, :edit, :update, :destroy]
# GET /doctors
# GET /doctors.json
def index
#doctors = Doctor.all
end
# GET /doctors/1
# GET /doctors/1.json
def show
end
# GET /doctors/new
def new
#doctor = Doctor.new
end
# GET /doctors/1/edit
def edit
end
# POST /doctors
# POST /doctors.json
def create
#doctor = Doctor.new(doctor_params)
respond_to do |format|
if #doctor.save
format.html { redirect_to #doctor, notice: 'Doctor was successfully created.' }
format.json { render action: 'show', status: :created, location: #doctor }
else
format.html { render action: 'new' }
format.json { render json: #doctor.errors, status: :unprocessable_entity }
end
end
end
# PATCH/PUT /doctors/1
# PATCH/PUT /doctors/1.json
def update
respond_to do |format|
if #doctor.update(doctor_params)
format.html { redirect_to #doctor, notice: 'Doctor was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #doctor.errors, status: :unprocessable_entity }
end
end
end
# DELETE /doctors/1
# DELETE /doctors/1.json
def destroy
#doctor.destroy
respond_to do |format|
format.html { redirect_to doctors_url }
format.json { head :no_content }
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_doctor
#doctor = Doctor.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def doctor_params
params.require(:doctor).permit(:name, :surname, :gender, :birthday, :identity_number, :identity_number_pd, :image_url, :father_name, :doctor_specialty, :doc_medical_association_city, :doc_medical_association_no, :home_phone, :mobile_phone, :home_address, :city, :country, :postal_code, :email, :notes)
end
end
The count by 1 problem apparently is caused by unhealthy validations. I was using an email validator which caused the problem. So if anyone has the same problem, try disabling one by one app/models/your_model_validations.rb and see how it goes.

Rails Rspec error "undefined method" (railsturoial Chapter 10)

I'm going through Michael Hartl's priceless tutorial and I got stuck with some Rspec errors. I've double checked everything but it seems like I'm still missing something. Here's what the error messages look like.
The thing that's bothering me the most is when I was generating the Microposts model I accidentally made a typo in one of the options so I did rails destroy model Microposts to undo the generate command before generating the model again. I'm wondering if that has anything to do with the errors I'm seeing.
I really wish to finish this tutorial ASAP so I can get on with building my own web application. ANY help would be appreciated.
Here's what my code looks like.
micropost_pages_spec.rb
require 'spec_helper'
describe "MicropostPages" do
subject {page}
let(:user) {FactoryGirl.create(:user)}
before {sign_in user}
describe "micropost creation" do
before {visit root_path}
describe "with invalid information" do
it "should not create a micropost" do
expect {click_button "Post"}.not_to change(Micropost, :count)
end
describe "error messages" do
before {click_button "Post"}
it {should have_content('error')}
end
end
end
end
microposts_controller.rb
class MicropostsController < ApplicationController
before_filter :signed_in_user, only: [:create, :destroy]
def create
#micropost = current_user.micropost.build(params[:micropost])
if #micropost.save
flash[:success] = "Micropost created!"
redirect_to root_path
else
render 'static_pages/home'
end
end
def destroy
end
end
static_pages_controller.rb
class StaticPagesController < ApplicationController
def home
#micropost = current_user.microposts.build if signed_in?
end
def help
end
def about
end
def contact
end
end
user.rb (User model)
class User < ActiveRecord::Base
attr_accessible :email, :name, :password, :password_confirmation
has_secure_password
has_many :microposts, dependent: :destroy
before_save {self.email.downcase!}
before_save :create_remember_token
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-.]+\.[a-z]+\z/i
validates :name, presence: true, length: {maximum: 50}
validates :email, presence: true, format: {with: VALID_EMAIL_REGEX},
uniqueness: {case_sensitive: false}
validates :password, presence: true, length: {minimum: 6}
validates :password_confirmation, presence: true
private
def create_remember_token
self.remember_token = SecureRandom.urlsafe_base64
end
end
The error is with this line:
#micropost = current_user.micropost.build(params[:micropost])
It should be:
#micropost = current_user.microposts.build(params[:micropost])
You're using micropost when you should be using microposts.

Resources