Is possible to update database data inside a migration?
I have this migration:
class FixTokenAuth < ActiveRecord::Migration
def change
unless column_exists? :users, :provider
add_column :users, :provider, :null => false
end
unless column_exists? :users, :uid
add_column :users, :uid, :null => false, :default => ""
end
unless column_exists? :users, :tokens
add_column :users, :tokens, :text
end
end
end
And I have also to add indexes
add_index :users, [:uid, :provider], :unique => true
Of course the migration fail: uid is "" per default and it can't be unique.
After the creation of the column I need to execute a block on my User model:
User.all.each{|u|
u.provider = "email"
u.save!
}
Doing this 'uid' field is filled by data.
Is possible to add something to a migration?
The migration is just plain ruby code, which gets executed, so the best thing you could do is change the change method into up and down. In these methods you can safely write your updating code after the add_columnstatements.
rails generate devise User I got this=>
class DeviseCreateUsers < ActiveRecord::Migration
def self.up
create_table(:users) do |t|
t.database_authenticatable :null => false
t.recoverable
t.rememberable
t.trackable
# t.encryptable
# t.confirmable
# t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both
# t.token_authenticatable
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
# add_index :users, :authentication_token, :unique => true
end
def self.down
drop_table :users
end
end
But i want to create a users table with username, email, password, role, group, mark, created_at, modified_at columns.
How can i do this ?
Is this structure correct to have username, password, email, group, role, mark ?
class DeviseCreateUsers < ActiveRecord::Migration
def self.up
create_table(:users) do |t|
t.database_authenticatable :null => false
t.recoverable
t.rememberable
t.trackable
# t.encryptable
# t.confirmable
# t.lockable :lock_strategy => :failed_attempts, :unlock_strategy => :both
# t.token_authenticatable
t.string :username
t.string :password
t.string :email
t.string :group
t.string :role
t.integer :mark
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
# add_index :users, :authentication_token, :unique => true
end
def self.down
drop_table :users
end
end
What are these?
t.database_authenticatable :null => false
t.recoverable
t.rememberable
t.trackable
You can perform a migration to add some fields to the user table.
For example:
rails g add_fields_to_users username:string # as well as other fields you need
Then, in order to add columns to your table run:
rake db:migrate
Devise has already generated some columns you need like: email, password, created_at, updated_at...
For adding roles to your user model you should watch the cancan screencast: railscasts and also read the doc in order to see some updates.
EDIT:
If you want to add fields manually you could add them in your self.up method before running your migration:
def self.up
create_table(:users) do |t|
#...
t.rememberable
t.trackable
t.string :username
#... your other attributes here
end
Current migration:
t.string "email", :default => "", :null => false
add_index :users, :email, :unique => true
I want to create a new migration to remove the :null => false requirement and also remove the default => "" for email. Also, I would like to change the index to remove :unique => true. What's the syntax?
I haven't done much with indices, and there doesn't seem to be a change_index method on ActiveRecord::Migration, but you can try something like this:
class ChangeUserStuff < ActiveRecord::Migration
def self.up
change_column :users, :email, :default => "", :null => true
remove_index :users, :column => :email
add_index :users, :email
end
def self.down
change_column :users, :email, :default => "", :null => false
remove_index :users, :column => :email
add_index :users, :email, :unique => true
end
end
There was some funny behavior regarding changing :null options, but I believe setting them to true instead of omitting should handle it.
I have a migration AddAuthenticableToUser. (rake db:migrate:up VERSION=..) works fine, but when I'm trying to rollback a migration (rake db:migrate:down VERSION=..) it doesn't works. Any errors or warnings. Could you help me with this ?
def self.up
change_table :users do |t|
t.token_authenticatable
end
add_index :users, :authentication_token, :unique => true
end
def self.down
remove_index :users, :authentication_token
remove_column :users, :authentication_token
end
This should be the trick. I think you named your table token_authenticatable and then tried to remove authentication_token.
def self.up
create_table :reviews do |t|
t.column :authentication_token
end
add_index :users, :authentication_token, :unique => true
end
def self.down
remove_index :users, :authentication_token
remove_column :users, :authentication_token
end
A number of Rails 2.3 apps are using Restful Authentication but that plugin seems to have some issues with Rails 3. In upgrading to Rails 3 I have been using Devise. Is there any way to smoothly transition from Restful Authentication to Devise? Has anyone done a migration that shows how to update the User model?
Here is a good guide on migration from restful_authentication to devise
https://github.com/plataformatec/devise/wiki/How-To:-Migrate-from-restful_authentication-to-Devise
Reason for edit: prior link took folks to a blank page.
I updated my application from Restful Authentication to Devise already. Here is my migration:
class AlterUsersForDevise < ActiveRecord::Migration
def self.up
remove_column :users, :name
change_column :users, :email, :string, :default => "", :null => false, :limit => 128
rename_column :users, :crypted_password, :encrypted_password
change_column :users, :encrypted_password, :string, :limit => 128, :default => "", :null => false
rename_column :users, :salt, :password_salt
change_column :users, :password_salt, :string, :default => "", :null => false, :limit => 255
add_column :users, :reset_password_token, :string
change_column :users, :remember_token, :string, :limit => 255
rename_column :users, :remember_token_expires_at, :remember_created_at
add_column :users, :sign_in_count, :integer, :default => 0
add_column :users, :current_sign_in_at, :datetime
add_column :users, :last_sign_in_at, :datetime
add_column :users, :current_sign_in_ip, :string
add_column :users, :last_sign_in_ip, :string
rename_column :users, :activation_code, :confirmation_token
change_column :users, :confirmation_token, :string, :limit => 255
rename_column :users, :activated_at, :confirmed_at
add_column :users, :confirmation_sent_at, :datetime
end
def self.down
add_column :users, :name, :string, :limit => 100, :default => ""
rename_column :users, :encrypted_password, :crypted_password
change_column :users, :crypted_password, :string, :limit => 40
rename_column :users, :password_salt, :salt
change_column :users, :salt, :string, :limit => 40
remove_column :users, :reset_password_token
change_column :users, :remember_token, :string, :limit => 40
rename_column :users, :remember_created_at, :remember_token_expires_at
remove_column :users, :sign_in_count
remove_column :users, :current_sign_in_at
remove_column :users, :last_sign_in_at
remove_column :users, :current_sign_in_ip
remove_column :users, :last_sign_in_ip
rename_column :users, :confirmation_token, :activation_code
change_column :users, :confirmation_token, :string, :limit => 40
rename_column :users, :confirmed_at, :activated_at
remove_column :users, :confirmation_sent_at
end
end
My application isn't live so far. So i use the password encryption from Devise instead the one from Restful Authorization. If you application is already alive, and you have active users you should configure Devise to use SHA1 from Restful Authentication to en- and decrypt passwords. Otherwise all your users must request a new password.
You can configure this in the devise initializer.
Hope that helps...
Here's how to overcome the password problem:
You need to make a custom encryptor like so:
# /config/initializers/devise_encryptor.rb
require "digest/sha1"
module Devise
module Encryptors
class OldRestfulAuthentication < Base
def self.digest(password, stretches, salt, pepper)
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
end
end
end
end
And then choose it in devise.rb like so:
config.encryptor = :old_restful_authentication
That should do it!
I was having problems with the password encryption (but I found the answer, see my other response). The old app used an old version of Restful Authentication. It was handling the password encryption like so:
# before filter
def encrypt_password
return if password.blank?
self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{login}--") if new_record?
self.crypted_password = encrypt(password)
end
# Encrypts some data with the salt.
def self.encrypt(password, salt)
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
end
# Encrypts the password with the user salt
def encrypt(password)
self.class.encrypt(password, salt)
end
If I set Devise's config.encryptor to :restful_authentication_sha1 it doesn't work.
In my case it works (analized authentication.rb and by_password.rb in old gem restful_authentication):
config/initializers/devise.rb add this:
config.encryptor = :restful_authentication
config.stretches = 10 #REST_AUTH_DIGEST_STRETCHES frome Restful Authentication file config/initializers/site_key.rb
config.pepper = 'mashauronilavrechkumyachik' #REST_AUTH_SITE_KEY frome Restful Authentication file config/initializers/site_key.rb
app/models/user.rb add :encryptable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:encryptable, :omniauthable, :authentication_keys => [:login]
config/initializers/devise_encryptor.rb create with this this:
# -*- encoding : utf-8 -*-
require "digest/sha1"
module Devise
module Encryptable
module Encryptors
class RestfulAuthentication < Base
def self.digest(password, stretches, salt, pepper)
digest = pepper
stretches.times do
digest = secure_digest(digest, salt, password, pepper)
end
digest
end
def self.secure_digest(*args)
Digest::SHA1.hexdigest(args.flatten.join('--'))
end
def self.encrypt_password
return if password.blank?
self.password_salt = make_token if new_record?
self.encrypted_password = encrypt(password)
end
def self.make_token
secure_digest(Time.now, (1..10).map{ rand.to_s })
end
def self.encrypt(password)
self.password_digest(password, stretches, salt, pepper)
end
end
end
end
end