Devise remember me not storing cookie - ruby-on-rails-3

I've set up a simple sample app that uses devise for user authentication.
When I select the rember me checkbox on login I get the following in the console:
Processing by Devise::SessionsController#create as HTML
Parameters: {"commit"=>"Sign in", "authenticity_token"=>"Vm+2aWEmCRnnjdXAOpXdI5dGChUKlEcmfGNXNoGUkwc=", "utf8"=>"Γ£ô", "user"=>{"remember_me"=>"1", "password"
=>"[FILTERED]", "email"=>"test#example.com"}}
←[1m←[35mUser Load (1.0ms)←[0m SELECT "users".* FROM "users" WHERE "users"."email" = 'test#example.com' LIMIT 1
←[1m←[36mAREL (1.0ms)←[0m ←[1mUPDATE "users" SET "last_sign_in_at" = '2011-10-06 21:36:46.439511', "updated_at" = '2011-10-06 21:43:59.298269', "sign_in_coun
t" = 15, "current_sign_in_at" = '2011-10-06 21:43:59.297269' WHERE "users"."id" = 1←[0m
I have the following in my Posts controller:
before_filter :authenticate_user!
However, when I close the browser and open it again I am forced to login again before I can view posts. It doesn't seem that the cookie is being stored. I found the following cookie in firefox for my page:
Cookie Name: remember_user_token
Expires: at end of session
Is this the cookie thats supposed to be stored and expire at a future date but instead expires at the end of session? Can someone verify this?
I've tried both commenting and uncommenting config.remember_for = 2.weeks in devise.rb to different settings and nothing seems to fix the problem.
My User.rb file looks like this:
class User < ActiveRecord::Base
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

Related

One to one in rails aplication

i have question about proper way to do one to one association in rails.
I am using Devise GEM as user module and all users can have only one company so i made
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
has_one :company
end
and
class Company < ActiveRecord::Base
belongs_to :user
end
What is proper way to create company?? normally i made it like this:
i check if company exist if exist display message if not proceed to create. Is that good method?
def new
if Company.exists?(:user_id => current_user.id )
flash[:notice] = "Only One company is allowed."
redirect_to(:action => 'index')
end
end
def create
# Instantiate a new object using form parameters
#company = Company.new(company_params)
##company = Company.new(params[:page].merge(:user_id => 1))
# Save the object
if #company.save
# If save succeeds, redirect to the index action
flash[:notice] = "Company created successfully."
redirect_to(:action => 'index')
else
# If save fails, redisplay the form so user can fix problems
render('new')
end
end
If your form is properly created, it should be OK.
in your User form, you should use fields_for, and it should look like something like this :
<%= f.fields_for :company do |company_field| %>
<%= company_field.text_field :name %>
<% end %>
Edit : Don't forget to add nested attibutes : accepts_nested_attributes_for :address on the model user, below the has_one :company.
Nested attributes allow you to save attributes on associated records
through the parent.
Beside that, be carefull with the validation you wanted to do in the new method, the proper way to handle validation is to use ActiveRecord Validations.

devise in rails 3 : 'user_signed_in?' false 'signed_in?' true 'current_user' nil

I am migrating a Rails 2 app to Rails 3 and had to use a new authentication solution since restful_authentication is no longer supported. I am trying out Devise and am having problems with it.
I have a login page, which then directs you to the app. You can also use the app without logging in but some options are not available until you login.
Once logging in Devise says that I have logged in via a flash message, but any current_user will evaluate to nil, current_user.blank? evaluates to true and any user_signed_in? will evaluate to false. Oddly signed_in? evaluates to true. Checking my session data shows that warden.user.user.id contains the correct user id and a csrf token exists. This is true both in the view and in the controller.
Here is routes.rb
MyApp::Application.routes.draw do
devise_for :users
match "/:controller(/:action(/:id))"
match "/:controller(/:action(/:id))(.:format)"
match "/:controller(/:action(.:format))"
devise_scope :user do
get 'signup', :to => 'devise/registrations#new'
get 'login', :to => 'devise/sessions#new'
get 'signout', :to => 'devise/sessions#destroy'
end
root :to => 'main#design'
end
User.rb
require 'digest/sha1'
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :confirmable, :validatable,
:encryptable, :encryptor => :restful_authentication_sha1
attr_accessible :email, :password, :password_confirmation, :remember_me, :profile_company, :profile_state, :profile_city, :profile_postcode, :profile_country, :profile_phone, :profile_address
validates_length_of :name, :maximum => 100
validates_presence_of :email
validates_length_of :email, :within => 6..100
validates_uniqueness_of :email
def profile_complete?
if !(self.profile_address.blank? || self.profile_city.blank? || self.profile_state.blank? || self.profile_phone.blank? || self.name.blank? || self.state != 'active')
true
else
false
end
end
end
I've seen a lot of similar questions on SO, but none of the answers seem to fit my scenario. Any help would be greatly appreciated, thanks!
EDIT: warden.authenticate(:scope => :user) returns what i would expect current_user to return.
I believe that I have solved this issue, the restful_authentication plugin added a UsersHelper file that I believe was somehow interfering with how Devise was handling the User class.

Devise - mass assignment error when changing other users passwords in specific password change page

In my RoR application I'm using devise and the client requires a bit of customisation - basically he requires that the administrator be able to change passwords of other users and that the password change page be different than the page to edit profile details. I've set up custom actions to handle this namely my own change_password action in users controller.
Users Controller Actions
def change_password
#user = User.find(params[:id])
end
def update_password # I post to this
#user = User.find(params[:id])
if #user.update_attributes!(params[:user])
redirect_to users_path, :notice => "User updated."
else
redirect_to users_path, :alert => "Unable to update user."
end
end
Heres the routes.rb entries
devise_for :users, :skip => [:registrations]
as :user do
get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
put 'users' => 'devise/registrations#update', :as => 'user_registration'
end
resources :users
...
match "/users/:id/change_password" =>"users#change_password", :as=>:change_password_user, :via=>:get
match "/users/:id/update_password" => "users#update_password", :as=>:update_password_user, :via=>:post
And this is my users model
class User < ActiveRecord::Base
rolify
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable, :registerable,
devise :database_authenticatable, #:registerable,
:recoverable, :rememberable, :trackable, :validatable
# Setup accessible (or protected) attributes for your model
attr_accessible :role_ids, :as => :admin
attr_protected :username, :name, :email, :password, :password_confirmation, :remember_me
validates_uniqueness_of :username
validates_presence_of :username, :email
validates_uniqueness_of :email
end
however I keep getting this mass attributes assignment error
Can't mass-assign protected attributes: password, password_confirmation
the weird thing is that I've set all these attributes to accessible_protected. I can edit other users details but can't edit their passwords. Whats going on here?
There are many ways you can fix this problem. I'll try to explain a few.
I think the key to your problem is that you are mixing up the MassAssignmentSecurity roles. You've defined a Whitelist for the admin role and a Blacklist for the default role. The error says that you tried to assign something that was on the Blacklist for the default role.
Since you are defining different roles, I assume you probably want to fix it this way:
Change your admin Whitelist
attr_accessible :role_ids, :password, :password_confirmation, as: :admin
Then assign as the admin:
if #user.update_attributes!(params[:user], as: :admin)
(If your controller action includes fields other than the password fields, this may cause new violations.)
A different option is to stick to the default role. You can bypass security a couple ways.
The first option which I don't recommend is to not pass the password and password confirmation as part of the User params, and send them separately in your view. You can then manually set those fields like so:
#user.assign_attributes(params[:user])
#user.password = params[:password]
#user.password_confirmation = params[:password_confirmation]
if #user.save!
However, it's even easier to do the following to just skip protection:
#user.assign_attributes(params[:user], without_protection: true)
if #user.save!
For more information, this guide is fairly good:
http://guides.rubyonrails.org/security.html#mass-assignment
I hope that helps.

Uniqueness of users with devise and acts_as_tenant in rails 3

I am using the acts_as_tenant gem to manage multi-tenancy, and I'm using devise to manage users.
I have only setup devise User model and Account model for tenants.
I can create users against multiple tenants - this is all working fine EXCEPT when I attempt to create two users with the same email against different tenant ID's I get a uniqeness error.
I am using the validates_uniqueness_to_tenant option as described.
User model
class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me
acts_as_tenant(:account)
validates_uniqueness_to_tenant :email
end
Account model
class Account < ActiveRecord::Base
attr_accessible :name
end
Application Controller
class ApplicationController < ActionController::Base
set_current_tenant_by_subdomain(:account, :subdomain)
protect_from_forgery
end
This looks like it should be working based on all documentation in acts_as_tenant, do I need to override something at the devise level instead?
EDIT: After some head-scratching and a bit of a break, the problem is I believe because by default Devise has added a unique index to the Email column.
This obviously does not gel with what acts_as_tenant wants to do...
I will try removing the index and see whether Devise pukes or not.
EDIT 2: OK, have officially given up on this for now. I have hand-rolled authentication for the main site and this is working properly with acts_as_tenant.
I can only assume some incompatibility between acts_as_tenant and Devise at some layer - beyond me to find it at this stage.
The only way to do this is by removing the validatable module from devise and run your own validations like so:
class User < ActiveRecord::Base
acts_as_tenant :account
attr_accessible :email, :password, :remember_me
#remove :validatable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable
#run own validations
#I've omitted any emailformatting checks for clarity's sake.
validates :email,
presence: true,
uniqueness: { scope: :account_id, case_sensitive: false }
validates :password,
presence: true,
length: { :in => 6..20 },
:if => :password_required?
protected
# copied from validatable module
def password_required?
!persisted? || !password.nil? || !password_confirmation.nil?
end
end
I haven't tested it, but I wonder if changing the order might help acts_as_tenant do its thing before devise takes over.
class User < ActiveRecord::Base
acts_as_tenant(:account)
validates_uniqueness_to_tenant :email
# Include default devise modules. Others available are:
# :token_authenticatable, :confirmable,
# :lockable, :timeoutable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
attr_accessible :email, :password, :password_confirmation, :remember_me
end
Just came across this question. Sweam's solution is pretty good.
But I prefer to not override the default behaviour. So I came up with this solution:
validate :remove_old_email_validation_error
validates_uniqueness_of :email, :allow_blank => true, :if => :email_changed?, :scope => [:account_id]
private
def remove_old_email_validation_error
errors.delete(:email)
end
We remove the default validation error for email, therefore ignoring the validation check, and we do our own validation again.
What I have added is from the Validatable module, but i have added :scope to it.
Its important to keep the order. Add the above code after the devise command.
I resolved it as:
validate :remove_old_uniquess_email_error
private
def remove_old_uniquess_email_error
errors.delete(:email) if self.company_id.nil? && errors[:email].present? && errors[:email] == ["already taken"]
end

Devise validates_uniqueness fails silently

This is my User model:
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :token_authenticatable, :confirmable, :timeoutable,
:recoverable, :rememberable, :trackable, :validatable,
:email_regexp => /^([^#\s]+)#((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
attr_accessible :email, :password, :password_confirmation, :remember_me, :name, :confirmed_at, :confirmation_token, :category_ids
validates_uniqueness_of :email, :case_sensitive => false
validates_confirmation_of :password
end
When I enter an email address that exists in the DB, my page doesn't re-load and I don't see any error messages or anything.
This is what I see in the log:
Started GET "/validators/uniqueness?case_sensitive=false&user%5Bemail%5D=abc%40email.com" for 127.0.0.1 at 2012-06-21 03:59:57 -0500
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" LIKE 'abc#email.com') LIMIT 1
Started GET "/validators/uniqueness?case_sensitive=false&user%5Bemail%5D=abc%40email.com" for 127.0.0.1 at 2012-06-21 03:59:57 -0500
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE ("users"."email" LIKE 'abc#email.com') LIMIT 1
Why are you trying to overwrite devise validations? Devise will handle everything.
Logs suggest that you are trying to make some kind of JS form validation, right? If so, try checking for existing user differently:
email = params[:email] || ""
#exists = User.where(:email=>email.downcase).count
"The solution is to perform fully customized validation instead, or to
override email validation like you did in your example"
See
https://github.com/bcardarella/client_side_validations/issues/455#issuecomment-12170527