I have this migration to the table users made with Devise, all worked fine until i tried to make a back office with active_admin gem and added a role, etc:
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :username, null: false, default: ""
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
t.string :confirmation_token
t.datetime :confirmed_at
t.datetime :confirmation_sent_at
t.string :unconfirmed_email # Only if using reconfirmable
t.timestamps
end
add_index :users, :email, unique: true
add_index :users, :username, unique: true
add_index :users, :reset_password_token, unique: true
add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
And this migration that add a column to the table:
class AddRoleToUsers < ActiveRecord::Migration
def change
add_column :users, :role, :string
User.create! do |u|
u.username = 'admin'
u.email = 'admin#example.com'
u.password = 'admin123'
u.role = 'administrator'
end
end
end
I do rake db:migrate and got this error:
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:
Record invalido/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord- 4.2.1/lib/active_record/validations.rb:79:in `raise_record_invalid'
/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/validations.rb:43:in `save!'
/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/attribute_methods/dirty.rb:29:in `save!'
/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/transactions.rb:291:in `block in save!'
/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord- 4.2.1/lib/active_record/transactions.rb:347:in `block in with_transaction_returning_status'
/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/connection_adapters/abstract/database_statements.rb:211:in `transaction'
/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/transactions.rb:220:in `transaction'
/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/transactions.rb:344:in `with_transaction_returning_status'
/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/transactions.rb:291:in `save!'
/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/persistence.rb:51:in `create!' /home/dev8/RedTwitter/db/migrate/20150605140226_add_role_to_users.rb:6:in `change'
/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/migration.rb:606:in `exec_migration'
/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/migration.rb:590:in `block (2 levels) in migrate'
/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/migration.rb:589:in `block in migrate'
/home/dev8/.rvm/gems/ruby-2.2.1/gems/activerecord-4.2.1/lib/active_record/connection_adapters/abstract/connection_pool.rb:292:in `with_connection'
........
I tried rake db:rollback and got a similar error.
What could it be?
EDIT:
User.rb
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :registerable, :confirmable, :authentication_keys => [:login]
attr_accessor :login
has_many :tweets , dependent: :destroy
validates :username,
:presence => true,
:uniqueness => {
:case_sensitive => false
}, length: { in: 6..20 }
def role?(role)
roles.include? role.to_s
end
def login=(login)
#login = login
end
def login
#login || self.username || self.email
end
def self.find_for_database_authentication(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions.to_hash).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
else
where(conditions.to_hash).first
end
end
end
I believe you need to call User.reset_column_information in your migration, after adding the new column, otherwise Rails doesn't know about it.
class AddRoleToUsers < ActiveRecord::Migration
def change
add_column :users, :role, :string
User.reset_column_information
u = User.new
u.username = 'admin'
u.email = 'admin#example.com'
u.password = 'admin123'
u.role = 'administrator'
u.save(:validate => false)
end
end
Use find or create method. This will allow you to not raise invalid record error if you already have user, so all later migrations will run well.
Related
I created an only API rails project and added devise user model
now I am trying to sign-up using Postman but it does not save the new user on the
database
however, it does not return an error as well.
Postman post request and parameters passed
My app controller with the additional permitted attributes
`class ApplicationController < ActionController::API
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
attributes = :name, { roles: [] }
devise_parameter_sanitizer.permit(:sign_up, keys: attributes)
devise_parameter_sanitizer.permit(:account_update, keys: attributes)
end
end`
Devise User model with validations
`class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
validates :name, presence: true
validates :password, presence: true
validates :email, presence: true
validates :roles, presence: true
has_many :reservations, dependent: :destroy
has_many :vechiles, through: :group_entities
end`
The migration file for the devise user table
class DeviseCreateUsers < ActiveRecord::Migration[7.0]
def change
create_table :users do |t|
t.string :name, null: false
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
# t.integer :sign_in_count, default: 0, null: false
# t.datetime :current_sign_in_at
# t.datetime :last_sign_in_at
# t.string :current_sign_in_ip
# t.string :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
Roles col. added to user table
class AddRolesToUsers < ActiveRecord::Migration[7.0]
def change
add_column :users, :roles, :text, array: true, default: []
end
end
My Routes.rb
# frozen_string_literal: true
Rails.application.routes.draw do
devise_for :users
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
resources :users, only: [:index]
# Defines the root path route ("/")
# root "articles#index"
end
I used devide in gem and now I made Sign up&Log in pages.
When I wrote my id and email address in my app,blowser told me 1 error prohibited this user from being saved: Id can't be blank.Of course,I surely wrote id,so I don't know why.
Is this blowser error?
I wrote in home_controller,
class HomeController < ApplicationController
before_filter :find_user, only: [:index]
def index
# #id = params[:id]
# #email = params[:email]
if id == #user.id && email == #user.email
render :text => "sucsess"
else
render :text => "fail"
end
end
def create
id = params[:id]
email = params[:email]
#user = UserData.new(user_params)
#user.save
unless userData.save
#error_message = errors.full_messages.compact
end
end
private
def find_user
user = User.find(params[:id])
if current_user.id != user.id
redirect_to root_path
end
end
end
in users.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
validates :id, presence: true
validates :email, presence: true, uniqueness: true
end
in migration file
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps null: false
end
add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true
end
end
in routes.rb
Rails.application.routes.draw do
get 'notes/new'
devise_for :users
root to: "home#index"
get 'home/index'
get 'home/create'
namespace :home, default: {format: :json} do
resources :index, only: :create
end
end
Validation runs before creation. So the id will have no chance of being created before you save.
Remove this
validates :id, presence: true
and don't set the id manually on the create action.
Remove below line from model, as ID is auto generated field.
validates :id, presence: true
Update create action in controller file as below,
def create
#user = User.new(user_params)
#user.save
unless #user.save
#error_message = errors.full_messages.compact
end
end
Replace "UserData" with "User" which is the model name as per your code.
Comment or remove below line
validates :id, presence: true
as id is create automatically by rails and no need to validate it.
And
In your controller, change private method code:
def find_user
#user = User.find(params[:id]) #replace user to #user
if current_user.id != user.id
redirect_to root_path
end
end
Devise 3.5.2, Rails 4.2.3
While logging in, I'm trying to pass a hidden role_id along with the email/password combination. I am allowing the same email to register again, on a different subdomain, which causes a different role_id to be passed. The email+role_id is the unique index for the user.
I can create a user, but cannot log in. When I submit the log in form, I am faced with the following error:
undefined method 'email' for #<ActionDispatch::Request:0x007fa21628bda0>
EDIT:
If anyone can explain the process of changing the email uniqueness validation to email+role_id (not either/or, but and), that's all I need to accomplish. Following that process properly may avoid this error.
Debugging info:
The POST parameters are as follows:
{"utf8"=>"✓",
"authenticity_token"=>"[FILTERED]",
"member"=>{"role_id"=>"1",
"email"=>"some.user#email.com",
"password"=>"[FILTERED]",
"remember_me"=>"0"},
"commit"=>"Log in"}
Here is my Member model:
class Member < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :lockable, :timeoutable, :omniauthable
belongs_to :role
def self.find_for_authentication(warden_conditions)
where(:email => warden_conditions[:email], :role_id => warden_conditions[:role_id]).first
end
end
In config/initializers/devise.rb, the following is set:
config.authentication_keys = [:email, :role_id]
config.request_keys = [:email, :role_id]
My views/devise/sessions/new.html.erb includes:
<%= f.hidden_field :role_id, :value => Role.find_by_name(current_subdomain).id %>
I adjusted vendor/bundle/ruby/1.9.1/gems/devise-3.5.2/lib/devise/models/validatable.rb by changing this line:
validates_uniqueness_of :email, allow_blank: true, if: :email_changed?
to:
validates_uniqueness_of :email, :scope => :role_id, allow_blank: true, if: :email_changed? #using subdomains for validation
The relevant database migrations for the member are found here:
...devise_create_members.rb
class DeviseCreateMembers < ActiveRecord::Migration
def change
create_table(:members) do |t|
## Database authenticatable
t.string :email, null: false, default: ""
t.string :encrypted_password, null: false, default: ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, default: 0, null: false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
t.string :confirmation_token
t.datetime :confirmed_at
t.datetime :confirmation_sent_at
t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
t.string :unlock_token # Only if unlock strategy is :email or :both
t.datetime :locked_at
t.timestamps null: false
end
add_index :members, :email, unique: true
add_index :members, :reset_password_token, unique: true
add_index :members, :confirmation_token, unique: true
add_index :members, :unlock_token, unique: true
end
...add_columns_to_member.rb
class AddColumnsToMember < ActiveRecord::Migration
def change
add_reference :members, :contact, index: true
add_reference :members, :role, index: true
add_reference :members, :ownership, index: true
add_column :members, :account_status, :string
end
end
...reindex_members_email_and_role.rb
class ReindexMembersEmailAndRole < ActiveRecord::Migration
def change
add_index :members, [:email, :role_id], :unique => true
end
end
The last item on the trace is:
vendor/bundle/ruby/1.9.1/gems/devise-3.5.2/lib/devise/strategies/authenticatable.rb:152:in `block in request_values'
keys = request_keys.respond_to?(:keys) ? request_keys.keys : request_keys
values = keys.map { |k| self.request.send(k) } <--ERROR THIS LINE
Hash[keys.zip(values)]
end
What am I missing?
To fix this, I changed my config/initializers/devise.rb to reflect the following:
config.request_keys = { role_id: false }
This fixed the issue, but still prevented the same email from signing up with a different role ID. To fix this, I removed :validatable from my User model and added:
validates_uniqueness_of :email, :case_sensitive => false, :scope => :role_id, :allow_blank => true, :if => :email_changed?
validates_format_of :email, :with => Devise.email_regexp, :allow_blank => true, :if => :email_changed?
validates_presence_of :password, :on=>:create
validates_confirmation_of :password, :on=>:create
validates_length_of :password, :within => Devise.password_length, :allow_blank => true
This allows the same email address to sign up with a different role_id.
I also changed the following in authenticatable.rb:
def request_values
keys = request_keys.respond_to?(:keys) ? request_keys.keys : request_keys
values = keys.map { |k| self.request[self.scope][k] }
# values = keys.map { |k| self.request.send(k) }
Hash[keys.zip(values)]
end
UPDATE
I got tired of always having to re-hack the devise library, especially after I updated gems or transferred the app. I found this page that offered a better work-around (still follow the step regarding validations the User model listed above):
(From https://github.com/plataformatec/devise/pull/3965)
Comment out the following line we edited above:
# config.request_keys = { role_id: false }
Edit the config.authentication_keys line as follows:
config.authentication_keys = { email: true, role_id: false }
The issue is that request_keys honors only predefined keys such as :subdomain.
That should work now for creating a combination of custom keys to authenticate with.
I am getting the following error when I try to sign in in my rails app. I used devise for authentication. My error is
NoMethodError in Devise::SessionsController#create
undefined method `current_sign_in_at'
My user model is
models/user.rb
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable
attr_accessible :admin,:first_name, :last_name, :profile_name, :college_name, :email, :password, :password_confirmation, :remember_me, :provider, :uid
def admin?
end
def self.find_for_facebook_oauth(auth)
where(auth.slice(:provider, :uid)).first_or_initialize.tap do |user|
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.info.email
user.password = Devise.friendly_token[0,20]
#user.name = auth.info.name # assuming the user model has a name
#user.image = auth.info.image # assuming the user model has an image
user.save!
end
end
end
My schema is
db/schema.rb
ActiveRecord::Schema.define(:version => 20140126101946) do
create_table "levels", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "users", :force => true do |t|
t.string "first_name"
t.string "last_name"
t.string "profile_name"
t.string "college_name"
t.string "email", :default => "", :null => false
t.string "encrypted_password", :default => "", :null => false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "provider"
t.string "uid"
t.boolean "admin", :default => false
end
add_index "users", ["email"], :name => "index_users_on_email", :unique => true
add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
end
The code in my devise_create_users.rb is
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
t.string :first_name
t.string :last_name
t.string :profile_name
t.string :college_name
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
My trackable was commented and I removed the comments and then ran rake db:migrate but nothing happened. Now I cannot remove trackable as I need it. What I need is that somehow I can keep my devise as it is and also add trackable to it in such a way that it gets added to the schema.rb as well.
To add new columns to existing tables, simply updating already run migration is not going to work as the schema is at a later version than your existing migration's version. If you wish to modify the existing migration, you could run a down migration with:
rake db:migrate:down VERSION=20140126101944 # use version of the user migration
Then modify the migration adding the new columns as you've already done, then run up migration using:
rake db:migrate:up VERSION=20140126101944 # use version of the user migration
A better approach is to add a new migration with the change if your application is already in production.
To add the trackable columns to existing users table:
class AddTrackableColumnsToUser < ActiveRecord::Migration
def change
change_table :users do |t|
## Trackable
t.add_column :sign_in_count, :integer, :default => 0
t.add_column :current_sign_in_at, :datetime
t.add_column :last_sign_in_at, :datetime
t.add_column :current_sign_in_ip, :string
t.add_column :last_sign_in_ip, :string
end
end
end
Then run db:migrate:
rake db:migrate
In your models/user.rb
Change
devise :database_authenticatable, :registerable, :recoverable, :rememberable,
:trackable, :validatable, :omniauthable
to
devise :database_authenticatable, :registerable, :recoverable, :rememberable,
:validatable, :omniauthable
i.e. remove :trackable
I am really new to rails and have been trying to work on building an application. I recently have installed devise and omniauth for facebook with great success after some time. When I was reading into devise, I noticed that Devise has a "forgot password" module built into it.
I have scoured the internet and for the life of me haven't figured out how to set it up. Is there any guide?I have been working for hours, but I haven't really had any results. How do I set this up? I am using rails 4.0 and the newest version of devise.
Thanks,
Routes
Omrails::Application.routes.draw do
resources :boards
resources :pins
get 'about' => "pages#about"
root :to => 'pins#index'
resources :tests, :birthdays
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }
end
Devise Migration:
class DeviseCreateUsers < ActiveRecord::Migration
def change
create_table(:users) do |t|
## Database authenticatable
t.string :email, :null => false, :default => ""
t.string :encrypted_password, :null => false, :default => ""
## Recoverable
t.string :reset_password_token
t.datetime :reset_password_sent_at
## Rememberable
t.datetime :remember_created_at
## Trackable
t.integer :sign_in_count, :default => 0, :null => false
t.datetime :current_sign_in_at
t.datetime :last_sign_in_at
t.string :current_sign_in_ip
t.string :last_sign_in_ip
## Confirmable
# t.string :confirmation_token
# t.datetime :confirmed_at
# t.datetime :confirmation_sent_at
# t.string :unconfirmed_email # Only if using reconfirmable
## Lockable
# t.integer :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
t.timestamps
end
add_index :users, :email, :unique => true
add_index :users, :reset_password_token, :unique => true
# add_index :users, :confirmation_token, :unique => true
# add_index :users, :unlock_token, :unique => true
end
end
User.rb
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable,
:registerable,
:rememberable,
:trackable,
:recoverable,
:validatable,
:omniauthable,
:omniauth_providers => [:facebook]
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me, :name, :birthday, :sex, :address, :mobile, :provider, :uid
has_many :pins, :dependent => :destroy
has_many :boards, :dependent => :destroy
def self.find_for_facebook_oauth(auth, signed_in_resource=nil)
user = User.where(:provider => auth.provider, :uid => auth.uid).first
unless user
user = User.create(name:auth.extra.raw_info.name,
provider:auth.provider,
uid:auth.uid,
email:auth.info.email,
password:Devise.friendly_token[0,20])
end
user
end
end
Devise consists of 10 modules and the one you're looking for is recoverable. In your devise model, you need to add :recoverable attribute for devise.