I am using authlogic to do my authentication. The current model that serves as the authentication model is the user model. I want to add a "belongs to" relationship to user which means that I need a foreign key in the user table. Say the foreign key is called car_id in the user's model. However, for some reason, when I do
u = User.find(1)
u.car_id = 1
u.save!
I get
ActiveRecord::RecordInvalid: Validation failed: Password can't be blank
My guess is that this has something to do with authlogic. I do not have validation on password on the user's model. This is the migration for the user's table.
def self.up
create_table :users do |t|
t.string :email
t.string :first_name
t.string :last_name
t.string :crypted_password
t.string :password_salt
t.string :persistence_token
t.string :single_access_token
t.string :perishable_token
t.integer :login_count, :null => false, :default => 0 # optional, see Authlogic::Session::MagicColumns
t.integer :failed_login_count, :null => false, :default => 0 # optional, see Authlogic::Session::MagicColumns
t.datetime :last_request_at # optional, see Authlogic::Session::MagicColumns
t.datetime :current_login_at # optional, see Authlogic::Session::MagicColumns
t.datetime :last_login_at # optional, see Authlogic::Session::MagicColumns
t.string :current_login_ip # optional, see Authlogic::Session::MagicColumns
t.string :last_login_ip # optional, see Authlogic::Session::MagicColumns
t.timestamps
end
end
And later I added the car_id column to it.
def self.up
add_column :users, :user_id, :integer
end
Is there anyway for me to turn off this validation?
Sure. Per the docs:
acts_as_authentic do |c|
c.ignore_blank_passwords = true
end
Related
I have a User model with uuid for id column.
Ahoy gem creates visits as expected but the user_id is wrong.
Any ideas?
ok. Got that. Ahoy gem doesn't work with user_id as UUID. It takes the first digits from uuid and stores that in user_id for Ahoy::Visit which could look like random value.
The solution is to change the user_id type to uuid.
This migration would do the trick:
class ChangeAhoyVisits < ActiveRecord::Migration[5.2]
def change
Ahoy::Visit.destroy_all
remove_column :ahoy_visits, :user_id, :bigint
add_column :ahoy_visits, :user_id, :uuid, foreign_key: true, null: true
add_index :ahoy_visits, :user_id
end
end
Probably need to add the same type: :uuid to the user_id column in the ahoy_events table as well. After a few rake db:rollback's I ended up modifying the original migration file that is created by rails generate ahoy:install to look like this before I ran the migration:
def change
create_table :ahoy_visits do |t|
t.string :visit_token
t.string :visitor_token
# the rest are recommended but optional
# simply remove any you don't want
# user
t.references :user, type: :uuid, foreign_key: true, index: true
# standard
t.string :ip
t.text :user_agent
t.text :referrer
t.string :referring_domain
t.text :landing_page
# technology
t.string :browser
t.string :os
t.string :device_type
# location
t.string :country
t.string :region
t.string :city
t.float :latitude
t.float :longitude
# utm parameters
t.string :utm_source
t.string :utm_medium
t.string :utm_term
t.string :utm_content
t.string :utm_campaign
# native apps
t.string :app_version
t.string :os_version
t.string :platform
t.datetime :started_at
end
add_index :ahoy_visits, :visit_token, unique: true
create_table :ahoy_events do |t|
t.references :visit
t.references :user, type: :uuid, foreign_key: true, index: true
t.string :name
t.jsonb :properties
t.datetime :time
end
add_index :ahoy_events, [:name, :time]
add_index :ahoy_events, :properties, using: :gin, opclass: :jsonb_path_ops
end
And after running this slightly modified migration rather than original everything seemed to populate properly on an 'ahoy.track' in the db.
I'm a bit new in Rails world and I try to add a new field in devise schema.
I found this :
rails generate model NAME [field[:type][:index] field[:type]
and tried to apply the command :
rails generate devise User linkedin:string
The process seemed correct :
invoke active_record
create db/migrate/20130902085306_add_devise_to_users.rb
insert app/models/user.rb
route devise_for :users
But when I launch a db:migrate it occures an error :
PG::Error: ERROR: column "email" of relation "users" already exists
What did I do wrong ? why does it say (and is it related) email is wrong while it was ok before ?
Thanks a lot !
Here is the migration file result :
class AddDeviseToUsers < ActiveRecord::Migration
def self.up
change_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
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 # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
## Token authenticatable
# t.string :authentication_token
t.string :linkedin
# Uncomment below if timestamps were not included in your original model.
# 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
# By default, we don't want to make any assumption about how to roll back a migration when your
# model already existed. Please edit below which fields you would like to remove in this migration.
raise ActiveRecord::IrreversibleMigration
end
end
Does your users table already have email field? It seems there is, you have to remove creating an email field again by removing it from migration and make sure it is not referenced twice in user.rb model
db/migrate/20130902085306_add_devise_to_users.rb
Ok!
I've found what was wrong : I created a new table instead of updating existing one.
So the good task was :
rails g migration add_columnLinkedin_to_users
Then adding in the new created migration file :
change_table :users do |t|
t.string :linkedin
end
And db:migrate was a success !
Thanks for your helps !
For example, if a user signs up using email johndoe#xyz.com, I want this user to be part of the "XYZ" network on my website. People will be only allowed to join their respective networks. There will be numerous networks on my website and they are all separate from each other. This is how the user table looks in schema.db
create_table "activities", :force => true do |t|
t.integer "trackable_id"
t.string "trackable_type"
t.integer "owner_id"
t.string "owner_type"
t.string "key"
t.text "parameters"
t.integer "recipient_id"
t.string "recipient_type"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "activities", ["owner_id", "owner_type"], :name => "index_activities_on_owner_id_and_owner_type"
add_index "activities", ["recipient_id", "recipient_type"], :name => "index_activities_on_recipient_id_and_recipient_type"
add_index "activities", ["trackable_id", "trackable_type"], :name => "index_activities_on_trackable_id_and_trackable_type"
create_table "users", :force => true do |t|
t.string "name"
t.string "email"
t.timestamp "created_at", :null => false
t.timestamp "updated_at", :null => false
t.string "password_digest"
t.string "remember_token"
t.boolean "admin", :default => false
end
I'm using activities to track the user model and I display them in a "feed". I would like to add something like this in view: "Username has joined the XYZ network." by tracking the user model.
Create a Network model. It's database table will contain a string called domain. A network will have many users; a user will belong to a network. Add a network_id string to the user model as well.
Associations and support methods should look like this:
class Network < ActiveRecord::Base
has_many :users
def peers
self.users
end
end
class User < ActiveRecord::Base
belongs_to :network
delegate :peers => :network
validates :network_id, :presence => true
# ...
end
Now this is possible:
#network.users
# => collection of all users in a network
#user.network
# => the network user belongs to
#user.peers
# => collection of all users within #user's network
# => note: this will include #user itself in the collection
When a user signs up, create or find a Network record containing the domain string extracted from the user's email address. When a user updates their email address, check if the domain has changed, and re-create or re-find a Network record with matching domain.
It is tempting to automate this in the model, but is properly implemented in the controller, specifically UsersController#create and UsersController#update.
def create
# ...isntantiate #user...
#
set_network_id_from_email(#user.email)
#
# ...save...
end
def update
# ...instantiate #user...
#
if #user.email != params[:user][:email]
set_network_id_from_email(params[:user][:email])
end
#
# ...update_attributes...
end
private
def set_network_id_from_email(addr)
if email = Mail::Address.new(addr)
#user.network_id = Network.find_or_create_by_domain(email.domain)
end
end
I am wondering how can i add devise to an existing database with a different user. Here I already have a customer model define and I want to change to allow devise to work on it.
I have created a new migration and inserted the code has follow
class AddDeviseToCustomer < ActiveRecord::Migration
def change
change_table :customers do |t|
#t.database_authenticatable
t.string :encrypted_password, :null => false, :default => '', :limit => 128
t.confirmable
t.recoverable
t.rememberable
t.trackable
t.token_authenticatable
t.timestamps
end
end
end
According to this it should work. https://github.com/plataformatec/devise/wiki/How-To:-change-an-already-existing-table-to-add-devise-required-columns. But when running rake db:migrate i get the following
undefined method `confirmable' for #<ActiveRecord::ConnectionAdapters::Table:0x9286a28>
I have run the following line
rails g devise:install
Any reason devise won't recognize it, do i need to do something to say customer is a devise??
Thanks in advance
It looks like that documentation is outdated.
Try using devise generator, it will create same migration, with correct parameters, it's ok if its an existing model:
rails g devise customer
it should create AddDeviseToCustomers migration
with something similar to this:
class AddDeviseToCustomers < ActiveRecord::Migration
def self.up
change_table(:customers) 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
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 # Only if lock strategy is :failed_attempts
# t.string :unlock_token # Only if unlock strategy is :email or :both
# t.datetime :locked_at
## Token authenticatable
# t.string :authentication_token
# Uncomment below if timestamps were not included in your original model.
# t.timestamps
end
def self.down
# By default, we don't want to make any assumption about how to roll back a migration when your
# model already existed. Please edit below which fields you would like to remove in this migration.
raise ActiveRecord::IrreversibleMigration
end
end
note that there is no more t.confirmable
def destroy
#dignity.destroy
end
Sorry, that's not code, that's just how I feel right now. I know there are a ton of beginner questions on Devise, I think I looked at almost every single one.
I have a very simple Devise setup in Rails 3. I did:
rails generate devise User
I'm also running the rails 3 GeoKit plugin,(not sure if that's relevant, just know that I have this other model) so I have another model called Location, and it acts_as_mappable.
Before I post the code, the basic problem is that I cannot seem to get user_id to auto-increment. It was my understanding that a bit of Rails magic should take care of this for me, if I add a column called user_id to Location class. (which I did through a migration.) and then simply set has_many and belongs_to accordingly. (see below)
I can't figure out why user_id is always nil. Does it have something to do with the way the Devise engine works? I am pretty sure I've made this type of association work in the past in the same way when I wasn't using Devise.
user.rb:
class User < ActiveRecord::Base
has_many :locations
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable, :lockable and :timeoutable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :email, :password, :password_confirmation, :remember_me
end
location.rb:
class Location < ActiveRecord::Base
belongs_to :user
attr_accessible :street_adress, :city, :state, :zip, :item, :user_id
acts_as_mappable :auto_geocode => true
def address
return "#{self.street_adress}, #{self.city}, #{self.state}, #{self.zip}, #{self.item}"
end
end
here is the migration that added the column:
class AddUseridToLocation < ActiveRecord::Migration
def self.up
add_column :locations, :user_id, :integer
end
def self.down
remove_column :locations, :user_id
end
end
And finally, here is the schema.rb:
ActiveRecord::Schema.define(:version => 20110213035432) do
create_table "locations", :force => true do |t|
t.string "street_adress"
t.string "city"
t.string "state"
t.string "zip"
t.float "lat"
t.float "lng"
t.datetime "created_at"
t.datetime "updated_at"
t.string "item"
t.integer "user_id"
end
create_table "users", :force => true do |t|
t.string "email", :default => "", :null => false
t.string "encrypted_password", :limit => 128, :default => "", :null => false
t.string "password_salt", :default => "", :null => false
t.string "reset_password_token"
t.string "remember_token"
t.datetime "remember_created_at"
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"
t.datetime "created_at"
t.datetime "updated_at"
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
EDIT: I'm okay with a RTFM response, as long as I can get a little push in the right direction. I have a suspicion that I need to tell rails something in the create action of my locations_controller.rb ? Someone just give me a little hint here!
def destroy
#dignity.destroy
end
Clearly the first thing to be done is:
raise self.esteem
You say you can't get user_id to "autoincrement". I think what you meant is that user_id is not being assigned (i.e. it is always nil). Can you show the part of the code that assigns a location to a user? Either of these should work:
#user.locations.build
#user.locations << Location.new
EDIT
To expand on this a bit, say you have a request that looks like this:
POST /users/37/locations
And the submitted form contains input name=user[location][name] value="Paris". A typical Rails controller create action might look like this:
def create
#user = User.find(params[:user_id])
#user.locations.build(params[:user][:location])
if #user.save
flash[:notice] = "Location created successfully"
redirect_to user_locations_path(#user)
else
render :new
end
end
The 'magic' is basically Rails inferring from the has_many statement that it needs to set the value of the foreign key column ('user_id') in the related row in the locations table. When you call #user.save it adds a new row in locations and sets user_id to the value of #user.id.