How do I enable :confirmable in Devise? - ruby-on-rails-3

The newest version of Devise doesn't have :confirmable enabled by default. I already added the respective columns to the User model but cannot find any code examples of how to enable :confirmable.
Where can I find a good example or what code do I need to enable it?

to "enable" confirmable, you just need to add it to your model, e.g.:
class User
# ...
devise :confirmable , ....
# ...
end
after that, you'll have to create and run a migration which adds the required columns to your model:
# rails g migration add_confirmable_to_devise
class AddConfirmableToDevise < ActiveRecord::Migration
def self.up
add_column :users, :confirmation_token, :string
add_column :users, :confirmed_at, :datetime
add_column :users, :confirmation_sent_at , :datetime
add_column :users, :unconfirmed_email, :string
add_index :users, :confirmation_token, :unique => true
end
def self.down
remove_index :users, :confirmation_token
remove_column :users, :unconfirmed_email
remove_column :users, :confirmation_sent_at
remove_column :users, :confirmed_at
remove_column :users, :confirmation_token
end
end
see:
Adding confirmable module to an existing site using Devise
I'd recommend to check the source code to see how Confirmable works:
https://github.com/plataformatec/devise/blob/master/lib/devise/models/confirmable.rb
You could also check the RailsCast on Devise:
http://railscasts.com/episodes/209-introducing-devise
Next it would be best to search for example applications on GitHub

This question seems to be odd one ;-) If you written some migration alike:
change_table(:users) do |t|
t.confirmable
end
add_index :users, :confirmation_token, :unique => true
and as you said little change in model (passing additional => :confirmable to devise) like so:
devise :database_authenticatable, :registerable, :confirmable
you can now generate some views (if you didn')
rails generate devise:views
You can go to app/views/devise/confirmations/new.html.erb and check how it looks like or change it. Furthermore you can inspect app/views/devise/confirmations/shared/_links.erb => there is line:
<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %>
This condition checks if confirmable is turned on so... technically if everything went fine it should works OOTB. After creating new account - in log - you should see lines where confirmation mail is sent with appropriate link. It triggers:
Rendered devise/mailer/confirmation_instructions.html.erb
so you have got next place where you can customize it a bit
How to customize confirmation strategy? Please ask exact question what do you want to achieve. You can check devise gem path. In /lib/devise/models/confirmable.rb some comments could be helpful.
regards

If you've already installed devise into your app, and want to add "confirmable" later, instead of running:
rails generate devise:views
as mentioned by Piotr, run
rails generate devise:views confirmable
to produce only the views needed for "confirmable". You'll see output like this:
rails generate devise:views confirmable
invoke Devise::Generators::SharedViewsGenerator
create app/views/confirmable/mailer
create app/views/confirmable/mailer/confirmation_instructions.html.erb
create app/views/confirmable/mailer/reset_password_instructions.html.erb
create app/views/confirmable/mailer/unlock_instructions.html.erb
create app/views/confirmable/shared
create app/views/confirmable/shared/_links.erb
invoke form_for
create app/views/confirmable/confirmations
create app/views/confirmable/confirmations/new.html.erb
create app/views/confirmable/passwords
create app/views/confirmable/passwords/edit.html.erb
create app/views/confirmable/passwords/new.html.erb
create app/views/confirmable/registrations
create app/views/confirmable/registrations/edit.html.erb
create app/views/confirmable/registrations/new.html.erb
create app/views/confirmable/sessions
create app/views/confirmable/sessions/new.html.erb
create app/views/confirmable/unlocks
create app/views/confirmable/unlocks/new.html.erb
You'll then be able to access these files directly in your project to style them like your application. You'll also be able to change the messaging in the emails Devise sends out through the generated mailer views.
Last, don't forget to add config.action_mailer.delivery_method and config.action_mailer.smtp_settings in your app/config/environments/{environment_name}.rb file. This is what my production.rb file looks like:
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => '[redacted]',
:user_name => '[redacted]',
:password => '[redacted]',
:authentication => 'plain',
:enable_starttls_auto => true }

Checkout devise wiki page. There is a full answer for your question.

For DRY, you can also put mailer config in config/initializers/mail.rb like:
ActionMailer::Base.smtp_settings = {
:address => "smtp.gmail.com",
:port => 587,
:domain => '[redacted]',
:user_name => '[redacted]',
:password => '[redacted]',
:authentication => 'plain',
:enable_starttls_auto => true }

After configuring the ActionMailer setting described above I had to make one last addition to the config/environments/development.rb file to fix an error page that would show up after registering a new user:
config.action_mailer.default_url_options = { :host => 'localhost' }
More details about this solution: Heroku/devise - Missing host to link to! Please provide :host parameter or set default_url_options[:host]

Related

How to check emptiness on devise custom fields?

I've added two news fields to my users table :first_name and :last_name
In migration file I've specified these fields couldn't be null using the following code:
class Userscustomfields < ActiveRecord::Migration
def change
add_column :users, :first_name, :string, {:null => false, :limit => "128"}
add_column :users, :last_name, :string, {:null => false, :limit => "128"}
end
end
I've checked on my database and the table was configurated correctly. But when I'm going to do a new register, my rails app allows to me to add a new user with first and last names empty. The app saves the fields with "", which didn't worked as I expected.
How can I do prevent this, by making a check of emptiness on my field before save them on my database?
I put on model user.rb
validates :first_name, :last_name, presence: true

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.

RSpec tests with devise: could not find valid mapping

I'm trying to run controller specs with devise 1.3.4. (and factory girl)
I followed the instructions in the git wiki for the project. I am able to log in as a user using the login_user method created in the macro, but login_admin fails with the following error:
...
sign_in Factory.create(:admin)
Could not find a valid mapping for #<User id: 2023, email: "admin1#gmail.com", .... >
Factory:
Factory.define :user do |f|
f.sequence(:username) {|n| "user#{n}"}
f.sequence(:email) {|n| "user#{n}#gmail.com"}
f.email_confirmation {|fac| fac.email }
f.password "a12345Den123"
f.password_confirmation "a12345Den123"
# f.admin 0
end
Factory.define :admin, :class => User do |f|
f.sequence(:username) {|n| "admin#{n}"}
f.sequence(:email) {|n| "admin#{n}#gmail.com"}
f.email_confirmation {|fac| fac.email }
f.password "a12345Den123"
f.password_confirmation "a12345Den123"
f.admin 1
end
Controller macros module:
module ControllerMacros
def login_admin
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user] #it should map to user because admin is not a model of its own. It produces the same result either way.
#admin = Factory.create(:admin)
sign_in #admin
end
end
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
#user = Factory.create(:user)
sign_in #user
end
end
end
routes
devise_for :users
devise_for :admins, :class_name => 'User'
One solution is to set cache_classes = false, however that isn't ideal as I use spork and don't want to have to restart it after changing a model.
Any help?
I have something like this in my routes:
devise_for :accounts, :controllers => {:confirmations => "confirmations"} do
put "confirm_account", :to => "confirmations#confirm_account"
get "login" => "devise/sessions#new", :as => :login
delete "logout" => "devise/sessions#destroy", :as => :logout
get "register" => "devise/registrations#new", :as => :register
end
so in my spec/support/controller_macros.rb I needed to change from:
def login_account
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:account]
#account = Factory.create(:account)
sign_in(#account)
end
end
to
def login_account
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:account]
#account = Factory.create(:account)
sign_in(:account, #account)
end
end
note the sign_in(scope, resource)
I hope this helps.
This is from the devise readme:
Devise also ships with default routes.
If you need to customize them, you
should probably be able to do it
through the devise_for method. It
accepts several options like
:class_name, :path_prefix and so on,
including the possibility to change
path names for I18n
So I would check your routes file and make sure this is in there:
devise_for :admins, :class_name => 'User'
You may want to check your code for multiple devise_for :admins declarations in different places. This has been the cause of such an exception in my case, as it surely confuses Devise.

Paperclip - undefined method 'icon_file_name'

I've just installed the Paperclip and trying to attach an icon to my model.
has_attached_file :icon,
:styles => { :normal => "100x100>", :format => 'png' },
:storage => :s3,
:s3_credentials => "#{RAILS_ROOT}/config/s3.yml",
:url => "/icon/:slug.:extension"
:path => "icon/:slug.:extension"
s3.yml contains my bucket name and two keys.
slug interpolation is defined in the config/initializers/paperclip.rb as
Paperclip.interpolates('slug') do |attachment, style|
attachment.instance.cached_slug
end
When I call game.icon.url, I get this error:
undefined method `icon_file_name' for #<Game:0x4000f50>
What am I doing wrong?
I'm running rails 3.0.4 and ruby 1.9.2 on Windows 7 x64, if it makes any difference.
Did you create a migration for your Game model to add in the appropriate fields that Paperclip needs? From the Paperclip documentation on Github:
class AddAvatarColumnsToUser < ActiveRecord::Migration
def self.up
add_column :users, :avatar_file_name, :string
add_column :users, :avatar_content_type, :string
add_column :users, :avatar_file_size, :integer
add_column :users, :avatar_updated_at, :datetime
end
def self.down
remove_column :users, :avatar_file_name
remove_column :users, :avatar_content_type
remove_column :users, :avatar_file_size
remove_column :users, :avatar_updated_at
end
end
After you've created that migration, you need to run the rake task to update your db: rake db:migrate
You can simply run - rails generate paperclip game icon
and it will generate the migration for you.
I made the same mistake, forgot to add the database migrations.
Here is a great article on doing this
even though it is on Heroku.
You can run the migrations like so
Create the migration file
rails g migration AddAvatarToUser
Then edit the file to the following
class AddAvatarToUser < ActiveRecord::Migration
def self.up
add_attachment :users, :avatar
end
def self.down
remove_attachment :users, :avatar
end
end
I had a similar problem, but it was working when I ran it in the browser, yet some of my tests were failing. You helped me realize that I had migrated my main development database, but I had failed to do a rake db:migrate test. Once I did that - problem disappeared.

Authlogic issue only in migration in rails 3 project

I'm trying to run the following migration
def self.up
add_column :users, :perishable_token, :string
User.all.each { |u| u.reset_perishable_token! }
change_column :users, :perishable_token, :string, :null => false
add_index :users, :perishable_token
end
and the u.reset_perishable_token! code behaves strangely (no return value, doesn't change the database field). Consequently change_column ..., :null => false fails with
users.perishable_token may not be NULL
Even separating the migration into two doesn't do the trick either if I run them with just one rake command.
Part One
def self.up
add_column :users, :perishable_token, :string
add_index :users, :perishable_token
end
Part Two
def self.up
User.all.each { |u| u.reset_perishable_token! }
change_column :users, :perishable_token, :string, :null => false
end
Only if I run the first and second migration in separate rake processes everything runs fine.
What could possibly be the reason and how can I fix it?
I think you need to add...
User.reset_column_information
...after you have added the perishable_token to the users_table, otherwise the User model is out of sync with the database.
I think the User model would only be loaded once per 'rake db:migrate', so it wouldn't help to split the migration in two.