I get the following error with the supplied code.
undefined method `password' for #<User:0x00000002e66980>
User Model
class User < ActiveRecord::Base
validates_presence_of :username
validates_presence_of :first_name
validates_presence_of :last_name
validates_presence_of :email
validates_uniqueness_of :username
validates_uniqueness_of :email
attr_accessor :password_confirmation
validates_confirmation_of :password
validate :password_non_blank
# password is a virtual attribute
def password=(pwd)
#password = pwd
return if pwd.blank?
create_new_salt
self.hashed_password = self.class.encrypt_password(pwd, self.password_salt)
end
def self.authenticate(username, password)
if user = self.find_by_username(username)
if user.hashed_password == encrypt_password(password, user.password_salt)
user
end
end
end
def User.encrypt_password(password, password_salt)
string_to_hash = password + "woozlewozzle" + password_salt
Digest::SHA1.hexdigest(string_to_hash)
end
private
def password_non_blank
errors.add(:password, "Password cannot be blank.") if hashed_password.blank?
end
def create_new_salt
self.password_salt = self.object_id.to_s + rand.to_s
end
end
Users Controller
class Admin::UsersController < Admin::AdminController
skip_before_filter :authorize
# GET /users
# GET /users.xml
def index
#users = User.find(:all, :order => :username)
respond_to do |format|
format.html # index.html.erb
end
end
# GET /users/1
# GET /users/1.xml
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
end
end
# GET /users/new
# GET /users/new.xml
def new
#user = User.new
respond_to do |format|
format.html # new.html.erb
end
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.xml
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
flash[:notice] = "User #{#user.first_name} #{#user.last_name} was created successfully."
format.html { redirect_to(:action => 'index') }
else
format.html { render :action => 'new' }
end
end
end
# PUT /users/1
# PUT /users/1.xml
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
flash[:notice] = "User #{#user.first_name} #{#user.last_name} was updated successfully."
format.html { redirect_to(:action => 'index') }
else
format.html { render :action => "edit" }
end
end
end
# DELETE /users/1
# DELETE /users/1.xml
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to(admin_users_url) }
end
end
end
Namespace Routes
namespace 'admin' do
get 'admin' => 'manage#index'
resources :users
end
User Form
<%= form_for(#user, :url => admin_users_path(#user)) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :username %><br />
<%= f.text_field :username %>
</div>
<div class="field">
<%= f.label :first_name %><br />
<%= f.text_field :first_name %>
</div>
<div class="field">
<%= f.label :last_name %><br />
<%= f.text_field :last_name %>
</div>
<div class="field">
<%= f.label :salutation %><br />
<%= f.text_field :salutation %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.text_field :email %>
</div>
<div class="field">
<%= f.label :password %><br />
<%= f.password_field :password %>
</div>
<div class="field">
<%= f.label :password_confirmation, 'Confirm Password' %><br />
<%= f.password_field :password_confirmation %>
</div>
<div class="actions">
<%= f.submit %>
</div>
<% end %>
Yes, you need attr_accessor :password and you don't need attr_accessor :password_confirmation as validates_confirmation_of :password will create it for you.
Related
Playing around with authentication from scratch and for some reason my users email address is not being saved to the DB. When I fire up the console and pull a random user, their email is always nil, but have validations set for the presence of email and am get a successful user created message. This was working before and not sure what broke it. I know this is something super simple but it has got me for the last few hours and am hoping a second pair of eyes can tell me what I'm doing wrong. GitHub link below
[https://github.com/smarandache1990/auth][1]
<h1>Sign Up</h1>
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_messages">
<h2>Form is invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :email %><br />
<%= f.text_field :email %>
<% #user.errors.full_messages_for(:email).each do |message| %>
<div><%= message %></div>
<% end %>
</p>
<p>
<%= f.label :password %><br />
<%= f.password_field :password %>
<% #user.errors.full_messages_for(:password).each do |message| %>
<div><%= message %></div>
<% end %>
</p>
<p>
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation %>
<% #user.errors.full_messages_for(:password_confirmation).each do |message| %>
<div><%= message %></div>
<% end %>
</p>
<p class="button"><%= f.submit %></p>
<% end %>
<h1>Sign In</h1>
<%= form_tag sessions_path do %>
<p>
<%= label_tag :email %><br />
<%= text_field_tag :email, params[:email] %>
</p>
<p>
<%= label_tag :password %><br />
<%= password_field_tag :password %>
</p>
<p class="button"><%= submit_tag "Log in" %></p>
<% end %>
class User < ApplicationRecord
attr_accessor :email, :password, :password_confirmation
before_save :encrypt_password
validates :password, confirmation: true, on: :create
validates :password_confirmation, presence: true
#validates_presence_of :password, :on => :create
#validates_confirmation_of :password
validates_presence_of :email
validates_uniqueness_of :email
def self.authenticate(email, password)
user = find_by_email(email)
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
class UsersController < ApplicationController
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to log_in_path, :notice => "Signed up!"
else
render :new, status: :unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
class SessionsController < ApplicationController
def new
end
def create
#user = User.authenticate(params[:email], params[:password])
if #user
session[:user_id] = #user.id
redirect_to root_url, :notice => "Logged in!"
else
flash.now[:notice] = "Wrong username or password"
render :new, status: :unprocessable_entity
end
end
def destroy
session[:user_id] = nil
redirect_to root_url, :notice => "Logged out!"
end
end
Remove the email from the attr_acessor (here).
attr_accessor creates the getters and setters for all attributes listed there. So, basically, you're overriding these methods for the email attribute.
About the validation, use this:
validates :email, presence: true, uniqueness: true
So summary: I wanted to have two types of users which are teachers and students. They are all users and therefore inherit from the users controller. The problem is no about the controllers or classes existing, it's how to adapt them through a form and whether or not I'm missing anything. I'm not sure how to do a backend to radio buttons and have tried things from previous answers but they result in errors. Also, how do I change routes based on which role they select? I have a registrations controller to override Devise.
Here is my form:
<div class="authform"> <%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :role => 'form'}) do |f| %>
<h2>Sign Up</h2>
<%= devise_error_messages! %>
<div class="form-group">
<%= f.label :name %>
<%= f.text_field :name, :autofocus => true, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :email %>
<%= f.email_field :email, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password %>
<%= f.password_field :password, class: 'form-control' %>
</div>
<div class="form-group">
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, class: 'form-control' %>
</div>
<div>
<%= f.radio_button :role, 'student' %>
<%= label :role_student, 'Student' %>
<%= f.radio_button :role, 'teacher' %>
<%= label :role_teacher, 'Teacher' %>
</div>
<%= f.submit 'Sign Up', :class => 'button right' %>
<% end %> </div>
I have a migration to add roles to users right here
class AddRoleToUsers < ActiveRecord::Migration
def change
add_column :users, :role, :integer
end
end
This was my original attempt on changing routes when adding roles (from another stack overflow question)
class RegistrationsController < Devise::RegistrationsController
def after_sign_up_path_for(resource)
if params[:user][:role] == 'student'
path_to_route = '/classrooms/index'
elsif [:user][:role] == 'teacher'
path_to_route = '/classrooms/new'
else
path_to_route = '/'
end
redirect_to path_to_route
end
end
Finally, here is my user's controller
class UsersController < ApplicationController
# before_action :authenticate_user!
before_action :logged_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
after_action :verify_authorized
# before_filter :check_role
def show
#user = User.find(params[:id])
authorize #user
#posts = #user.posts
end
def new
#user = User.new
authorize #user
end
#def after_sign_up_path_for(resource)
# if params[:user][:role] == 'student'
# path_to_route = '/classrooms/index'
# elsif [:user][:role] == 'teacher'
# path_to_route = '/classrooms/new'
# else
# path_to_route = '/'
# end
# redirect_to path_to_route
#end
def update
#user = User.find(params[:id])
authorize #user
if #user.update_attributes(secure_params)
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
def destroy
user = User.find(params[:id])
# authorize #user
user.destroy
redirect_to users_path, :notice => "User deleted."
end
def create_user_type
end
private
def secure_params
params.require(:user).permit(:role)
end
def logged_in_user
unless logged_in?
flash[:danger] = "Please log in."
redirect_to login_url
end
end
def correct_user
#user = User.find(params[:id])
redirect_to(root_url) unless #user == current_user
end
end
I know this is a bit of a long post, but I'd appreciate any help. Thanks so much! I love the rails community.
If you use simple_form you can use a standard input and assign the options to collection.
with simple_form
<%= f.input :role, collection: [:admin, :subscriber, :poster] %>
without simple_form
<%= f.select(:role, User.roles.keys.map {|role| [role.titleize,role]}) %>
user.rb
enum role: [:admin, :subscriber, :poster]
I have establish a Crud interface with devise below my code, the problem that I am running into is that When I try to create a user a get the following errors. I can't edit either. Please help.
"2 errors prohibited this user from being saved:
Email can't be blank
Password can't be blank"
of course I have been entering all of the information inclduding email and password. I follow the documentation from devise and have read some of this site Devise topics no such problem reported.
Controller:
class UsersController < ApplicationController
before_filter :authenticate_user!
before_action :authorized_user
# GET /users
# GET /users.json
def index
#users = User.all
# respond_to do |format|
# format.html index.html.erb
# format.json { render :json => #users }
end
# GET /users/1
# GET /users/1.json
def show
#user = User.find(params[:id])
# respond_to do |format|
# format.html show.html.erb
# format.json { render :json => #user }
end
# GET /users/new
# GET /users/new.json
def new
#user = User.new
# respond_to do |format|
# format.html new.html.erb
# format.json { render :json => #user }
end
# GET /users/1/edit
def edit
#user = User.find(params[:id])
end
# POST /users
# POST /users.json
def create
#user = User.new(params[:user_params])
respond_to do |format|
if #user.save
format.html { redirect_to #user, :notice => 'User was successfully created.' }
format.json { render :json => #user, :status => :created, :location => #user }
else
format.html { render :action => "new" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
# PUT /users/1
# PUT /users/1.json
def update
if params[:user][:password].blank?
params[:user].delete(:password)
params[:user].delete(:password_confirmation)
end
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user_params])
format.html { redirect_to #user, :notice => 'User was successfully updated.' }
format.json { head :ok }
else
format.html { render :action => "edit" }
format.json { render :json => #user.errors, :status => :unprocessable_entity }
end
end
end
# DELETE /users/1
# DELETE /users/1.json
def destroy
#user = User.find(params[:id])
#user.destroy
respond_to do |format|
format.html { redirect_to users_url }
format.json { head :ok }
end
end
private
def user_params
params.require(:user).permit(:username, :name, :lastname, :email, :password, :password_confirmation, :role_id)
end
def authorized_user
if current_user.role.name == "admin"
else
redirect_to :root, notice: "Not authorized" if #current_user.role.name == 'user' or nil?
end
end
end
Here is my form:
<%= form_for(#user) do |f| %>
<% if #user.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :username %><br />
<%= f.text_field :username, autofocus: true %>
</div>
<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name, autofocus: true %>
</div>
<div class="field">
<%= f.label :lastname %><br />
<%= f.text_field :lastname, autofocus: true %>
</div>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %>
<% if #minimum_password_length %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :role_id %><br />
<%= f.collection_select :role_id, Role.all, :id, :name_role_select %>
</div>
<div class="actions">
<%= f.submit "Sign up", class: 'button' %>
</div>
You aren't properly using your user_params.
Instead of this in your create action:
User.new(params[:user_params])
You need this, which calls your user_params method which is defined in your controller:
User.new(user_params)
Your original way is looking for params passed in from your request called 'user_params'(which doesn't exist).
Similarly, for your update action you need:
if #user.update_attributes(user_params)
#etc...
sign up page works fine but log in page password not correct then also form is logged in..pls help
This is my users.controller.rb which has new and create action
def new
#user = User.new
end
def create
#user = User.new(user_params)
if #user.save
redirect_to '/users/index', :notice => 'Signed In!'
else
render 'new'
end
end
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
This is my sessions.controller.rb which has new,create and destroy
def new
end
def create
user = User.authenticate(params[:email],[:password])
if user
session[:user_id]= user.id
redirect_to '/users/index', :notice => 'Logged In'
else
flash.now.alert = 'Invalid email or Password'
render 'new'
end
end
def destroy
session[:user_id]= nil
redirect_to root_url, :notice => 'Logged Out'
end
end
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
helper_method :current_user
private
def current_user
#current_user ||= User.find(session[:user_id]) if session[:user_id]
end
end
This is my new.html.erb for users controller-Sign Up Page
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class = "error_messages">
<h2>Form is Invalid</h2>
<ul>
<% for message in #user.errors.full_messages %>
<li> <%= message %> </li>
<% end %>
</ul>
</div>
<% end %>
<p>
<%= f.label :email %> <br />
<%= f.text_field :email %>
</p>
<p>
<%= f.label :password %> <br />
<%= f.password_field :password %>
</p>
<p>
<%= f.label :password_confirmation %> <br />
<%= f.password_field :password_confirmation %>
</p>
<p class = button> <%= f.submit %> </p>
<% end %>
This is my new.html.erb for sessions controller(Log In Page)
<%= form_tag sessions_path do %>
<p>
<%= label_tag :email %> <br />
<%= text_field_tag :email, params[:email] %>
</p>
<p>
<%= label_tag :password %> <br />
<%= password_field_tag :password,params[:password] %>
</p>
<p class=> <%= submit_tag %> </p>
<% end %>
This is User Model
class User < ActiveRecord::Base
attr_accessor :password
before_save :encrypt_password
validates_confirmation_of :password
validates_presence_of :password, :on => :create
validates_presence_of :email
validates_uniqueness_of :email
def self.authenticate (email, password)
user = find_by_email(email)
if user && user.password_hash = BCrypt::Engine.hash_secret(password, user.password_salt)
user
else
nil
end
end
def encrypt_password
if password.present?
self.password_salt = BCrypt::Engine.generate_salt
self.password_hash = BCrypt::Engine.hash_secret(password, password_salt)
end
end
end
You've fallen into the classic "single equals vs double equals trap"
if user && user.password_hash = BCrypt::Engine.hash_secret(password, user.password_salt)
should be
if user && user.password_hash == BCrypt::Engine.hash_secret(password, user.password_salt)
You compared password with single equal sign (=), which is not comparing rather assigning. So the condition returning true always.
Change your authenticate action into this:
def self.authenticate (email, password)
user = find_by_email(email)
hashed_password = BCrypt::Engine.hash_secret(password, user.password_salt)
if user && user.password_hash == hashed_password
user
else
nil
end
end
And you have typo in the following line in your Session Controller's create action:
user = User.authenticate(params[:email], params[:password])
I'm using Rails 4 to build a simple Admin interface for adding and removing users, or CRUD.
I'm currently having Devise installed and have built the basic views and actions.
However after filling out the forms myself, this is what I get:
2 errors prohibited this user from being saved:
Email can't be blank
Password can't be blank
This is what I have currently: (removed registerable since I don't want to have a public registration)
Models > user.rb
class User < ActiveRecord::Base
devise :database_authenticatable,
:recoverable, :rememberable, :trackable, :validatable
end
views > users > new.html.erb
<%= form_for #user do |f| %>
<% if #user.errors.any? %>
<div class="error_explanation">
<h2><%= pluralize(#user.errors.count, "error") %> prohibited this user from being saved:</h2>
<ul>
<% #user.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="field">
<%= f.label :password %>
<% if #validatable %>
<em>(<%= #minimum_password_length %> characters minimum)</em>
<% end %><br />
<%= f.password_field :password, autocomplete: "off" %>
</div>
<div class="field">
<%= f.label :password_confirmation %><br />
<%= f.password_field :password_confirmation, autocomplete: "off" %>
</div>
<div class="actions">
<%= f.submit "Create User" %>
</div>
<% end %>
routes.rb (currently I make new user through "/admin/users/new" )
Rails.application.routes.draw do
devise_for :users
scope '/admin' do
resources :users
end
end
Controllers > users_controller.rb
class UsersController < ApplicationController
def index
#users = User.all
end
def show
#user = User.find(params[:id])
end
def new
#user = User.new
end
def edit
#user = User.find(params[:id])
end
def create
#user = User.new(params[user_params])
if #user.save
redirect_to #user, :flash => { :success => 'User was successfully created.' }
else
render :action => 'new'
end
end
def update
#user = User.find(params[:id])
if #user.update_attributes(params[user_params])
sign_in(#user, :bypass => true) if #user == current_user
redirect_to #user, :flash => { :success => 'User was successfully updated.' }
else
render :action => 'edit'
end
end
def destroy
#user = User.find(params[:id])
#user.destroy
redirect_to users_path, :flash => { :success => 'User was successfully deleted.' }
end
private
def user_params
params.require(:user).permit(:email, :password, :password_confirmation)
end
end
Does anyone have any thoughts as to what is causing the error?
Thanks :D
Just a note: previously, before I disabled :registerable in devise_modules in user.rb, I can actually perform sign-ups using the default devise view "users/sign_up". However what I want is still to get an admin CRUD system, so I disabled it anyway.
Is it typo in your def create/update:
#user = User.new(params[user_params])
# should be
#user = User.new(user_params)
if #user.update_attributes(params[user_params])
# should be
if #user.update_attributes(user_params)