Devise allow email uniqueness within scope - ruby-on-rails-3

I'm in the process of upgrading a large project from rails 2 to rails 3, as a part of that upgrade I'm replacing a very old restful_athentication with devise.
The problem I'm having is that in the existing users table emails are validated like this.
validates_uniqueness_of :email, :scope => :account_id # No dupes within account
So if I add the index from the migration to add devise to users it WILL fail.
Is there a way that I can use
add_index :users, [:email,:account_id]
And have devise work properly?

I managed to get this working on my own, I added the following to config/initializer/devise.rb
config.authentication_keys = [ :email , :account_id]

Related

ActiveAdmin admin_users table devise users table logging in issue

Following is my setup
devise (4.4.3)
activeadmin (1.3.0)
Rails 5.2
I created a user table with devise. installed active admin and used the normal method and created admin_users table. NO I AM NOT USING THE SAME TABLE. THESE ARE DIFFERENT TABLES (I had to do this cause last time this question was marked as duplicate cause the user thought i used the same table)
Routes file looks like this:
devise_for :users
devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self)
devise_scope :user do
authenticated :user do
root 'home#dashboard', as: :authenticated_root
end
unauthenticated do
root 'devise/sessions#new', as: :unauthenticated_root
end
end
Now the issue is root_path '/' redirects correctly and I am able to login as User. But I am not able to login as Admin. It redirects me back to root_path that is unauthenticated user.
But weirdly when I login as user, I can then login as admin_user.
AGAIN I AM USING DIFFERENT TABLES, admin_users and users
Thanks in advance.
I can tell you an easy way to add admin in devise
$rails g migration add_admin_to_user
in the db
def change
add_column :users, :admin , :boolean , {default: false}
end
in user.rb
def admin?
admin
end
<% if current_user && current_user.admin? %>
<% end %>
then i do sign up from the email that i want to be the admin
then in rails c select the email that you want it to be the admin for example
User.last
user=User.last
user.admin=true
user
user.save
Solved this.
So the issue is when you have activeadmin admin_users and users table that is created with devise, and you place the authenticated_user! before_action in application_controller, activeadmin interprets it as authorization failure(though this should not be the case).
Solution to this is, go to active_admin.rb and add the following code
config.skip_before_action :authenticate_user!
This forces activeadmin to listen to only its authrization_adapter.

What does "null: false" really do?

I recently created a rails migration to add a Username to my devise Users.
add_column :users, :username, :string
I created a test account and signed up without entering a username. The registration went through and created a user with no user name. I had to fix this since I need a username to set the profile url. So I updated my migration to:
add_column :users, :username, :string, null: false
I thought this would prevent a user from creating a account with a null username - didn't work! I was still about to register with no username.
Eventually adding...
validates_presence_of :username
...to my user.rb model fixed the issue. But why didn't null:false stop it? Why should I keep it and how does it work?
This statement:
add_column :users, :username, :string, null: false
translates exactly to SQL DDL (Data Definition Language) standard:
ALTER TABLE users ADD username VARCHAR(255) NOT NULL;
The trailing NOT NULL is effect of null: false. You can use other column modifiers which some of them are directly translated into DDL.
Remember that if you already apply the migration to the database the further modifications should be done with a new migration file. Updates to migration Ruby files are not propagated to database schema when the migration was already applied. Eventually you can rollback last migrations and rerun them but then you may loose existing data during the schema rollback. See Changing Existing Migrations

Rails 3.2.20 setting up Devise :lockable

I have a Rails 3.2.20 app which uses Devise 2.1.2. Everything works fine, but Id like to add the :lockable feature to my project. After 5 failed attempts lock the account for 2 hours.
I've been reading over the Devise documentation and various StackOverflow questions and answers but I have a different setup than some.
I handle sessions in my own controller and also use the strategy to login via email or username from the Devise WiKi.
Here is my current setup:
routes.rb
devise_for :users, :controllers => { :sessions => "my_sessions" }
my_sesssions_controller.rb
class MySessionsController < Devise::SessionsController
skip_before_filter :check_concurrent_session
def create
super
set_login_token
end
private
def set_login_token
token = Devise.friendly_token
session[:token] = token
current_user.login_token = token
current_user.save(validate: false)
end
end
user.rb
attr_accessor :login
def self.find_first_by_auth_conditions(warden_conditions)
conditions = warden_conditions.dup
if login = conditions.delete(:login)
where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
else
where(conditions).first
end
end
config/initializers/devise.rb (Excerpt)
config.authentication_keys = [ :login ]
config.case_insensitive_keys = [ :username ]
config.strip_whitespace_keys = [ :username ]
So my question is, considering I handle sessions in my own controller and am also passing authentication via either email or username, how can I implement :lockable to lock out the account for 2 hours after 5 failed attempts?
I'm assuming there's a migration that I will need to generate and run, as well as setting the locking and unlocking strategy.
I read this post How to make devise lockable with number of failed attempts but I'm a bit unsure of the unlock_keys and how that works. Also in this post it talks about generating an index for the unlock_token, but I don't think I will need that since I'll be using a :time unlock_strategy.
Basically, I have Devise working well and I don't want to muddy the water or introduce any bugs into my project.
If anyone can help guide me through setting this up, I'd appreciate your assistance. Sorry if the question is redundant or not clear.
Thanks in advance for your help.

Rails 3 validate uniqueness ignores default scope on model

I'm using the permanent_records gem in my rails 3.0.10 app, to prevent hard deletes and it seems rails is ignoring my default scope in checking uniqueness
# user.rb
class User < AR::Base
default_scope where(:deleted_at => nil)
validates_uniqueness_of :email # done by devise
end
in my rails console trying to find a user by email that has been deleted results in null, but when signing up for a new account with a deleted email address results in a validation error on the email field.
This is also the case for another model in my app
# group.rb
class Group < AR::Base
default_scope where(:deleted_at => nil)
validates_uniqueness_of :class_name
end
and that is the same case as before, deleting a group then trying to find it by class name results in nil, however when I try to create a group with a known deleted class name it fails validation.
Does anyone know if I am doing something wrong or should I just write custom validators for this behavior?
Try scoping the uniqueness check with deleted_at
validates_uniqueness_of : email, :scope => :deleted_at
This can allow two records with the same email value as long as deleted_at field is different for both. As long as deleted at is populated with the correct timestamp, which I guess permanent_records gem does, this should work.

model missing required attr_accessor for 'photo_file_name' when uploading with paperclip and S3 on heroku

Setting up paperclip with S3 in my linux dev environment was a snap -- everything works out of the box. However, I can't get it to work on Heroku.
When I try to do an upload, the log shows:
Processing ItemsController#create (for 72.177.97.9 at 2010-08-26 16:35:14) [POST]
Parameters: {"commit"=>"Create", "authenticity_token"=>"0Hy3qvQBHE1gvFVaq32HMy2ZIopelV0BHbrSeHkO1Qw=", "item"=>{"photo"=>#<File:/home/slugs/270862_4aa601b_4b6f/mnt/tmp/RackMultipart20100826-6286-1256pvc-0>, "price"=>"342", "name"=>"a new item", "description"=>"a new item", "sold"=>"0"}}
Paperclip::PaperclipError (Item model missing required attr_accessor for 'photo_file_name'):
I found one blog post that referenced this error, and it said to add this to my model:
attr_accessor :photo_file_name
attr_accessor :photo_content_type
attr_accessor :photo_file_size
attr_accessor :photo_updated_at
That does indeed make the model missing required attr_accessor for 'photo_file_name' error go away, but it still doesn't work. See my other question for details. As I have figured out that with the attr_accessor lines added to my model the uploads fail even on my dev system, I suspect that is not the right answer.
Found the problem: needed to update the database.
heroku run rake:db:migrate
heroku restart
I had done what I thought would have accomplished the same thing already:
heroku rake db:schema:load
but perhaps that doesn't work or something went wrong in the process.
Error like this occurs if you create wrong column type in migration. When you define new table migration for paperclip, you need to specify t.attachment :name insted of t.string :name. Or add_attachment :table, :name when you add new paperclip column in existed table. And now you don't need to add these attributes in attr_accessor in model.
Well, this message seems to be because the columns it's missing. Try create a migration creating the columns:
class AddPhotoToEvent < ActiveRecord::Migration
def change
add_column :events, :photo_file_name, :string
add_column :events, :photo_content_type, :string
add_column :events, :photo_file_size, :integer
add_column :events, :photo_updated_at, :datetime
end
end
This work for me, here i have a table events with photo