Right now Devise generated edit.html.erb, which is great for editing essential info. However, I want to generate a new edit page, similar to edit.html.erb, but there, users will be able to edit other information about themselves.. I don't want to put everything on edit.html.erb because of UI.
So far I only added new columns to users table for a new edit page that I'm going to create.
Right now these are my routes:
devise_for :users, class_name: 'FormUser', :controllers => { omniauth_callbacks: 'omniauth_callbacks', registrations: 'registrations' }
root 'setup#index'
get '/setup' => 'setup#index'
get '/users/sign_out' => 'setup#index'
And this is my registration_controller.rb:
class RegistrationsController < Devise::RegistrationsController
def update_resource(resource, params)
if resource.encrypted_password.blank? # || params[:password].blank?
resource.email = params[:email] if params[:email]
if !params[:password].blank? && params[:password] == params[:password_confirmation]
logger.info "Updating password"
resource.password = params[:password]
resource.save
end
if resource.valid?
resource.update_without_password(params)
end
else
resource.update_with_password(params)
end
end
end
So I created a new controller with views but I have no idea what to put now in the routes.
Name of the new controller is styles_controller.rb and and views are fits.html.erb..
This script will generate controllers for you to override the behavior of Devise (but I highly recommend you do not do that):
https://github.com/plataformatec/devise/wiki/Tool:-Generate-and-customize-controllers
This shows you how to generate the view templates for you to override the default screens to login/etc.
https://github.com/plataformatec/devise#configuring-views
And this tutorial shows how to allow users to edit their profile without a password:
https://github.com/plataformatec/devise/wiki/How-To%3a-Allow-users-to-edit-their-account-without-providing-a-password
Related
I'm trying add a new button(Resend Email) to an existing(Send Email) method/route on Active Admin rails. I have done these kind of tasks on a normal rails with MVC architecture. Where I used to add the required route path in a html.erb file. I'm finding it quiet difficult to implement the same on Active Admin since it doesn't have that MVC look.
On routes.rb file I have
routes.rb
Rails.application.routes.draw do
mount Bootsy::Engine => '/bootsy', as: 'bootsy'
devise_for :admin_users, ActiveAdmin::Devise.config
ActiveAdmin.routes(self)
devise_for :users,controllers: {registrations: 'users/registrations',sessions: 'users/sessions',confirmations: 'users/confirmations'}
end
Here confirmations: 'users/confirmations' is used to send Email Verfication mail to the users. That's working fine. Some users forget to look into their email. So I'm trying to create a "Resend Email" button on the ActiveAdmin file, which on submitting sends the verification email mail again.
What path should I set inorder to send the mail again. I'm new to active-admin rails. Your help would be much appreciated.
User.rb
ActiveAdmin.register User, :as => 'User' do
action_item only: :show do
link_to('Resend Email', )
end
end
user_mailer.rb
def confirmation_instructions(record, token, opts={})
#system_email = SystemEmail.find_by(title: 'Email Verification')
#subject = #system_email.try(:subject).to_s
#subject = "Email Verification" if #subject.blank?
opts = {subject: #subject}
#token = token
devise_mail(record, :confirmation_instructions, opts)
end
I'm trying to make it so only admins can add uses with devise. I've gotten it mostly working however now when I'm logged in as an admin and submit the sign up form it kicks me back with the error: You are already signed in.
I've tried to follow the instructions here: http://wiki.summercode.com/rails_authentication_with_devise_and_cancan but it doesn't seem to mention this situation.
Do I need to do further overriding in the editors_controller to allow this?
Here are my routes ("editors" is the name of my user model):
devise_for :admins, :skip => [:registrations]
as :admin do
get 'admin/editors' => 'editors#index', as: :admin_editors
get 'admin/editors/new' => 'editors#new', as: :new_editor
delete 'admin/editors/:id' => 'editors#destroy', as: :destroy_editor
end
devise_for :editors, :skip => [:registrations], :controllers => { :registrations => "editors" }
and my editors_controller in "app/controllers/"
class EditorsController < Devise::RegistrationsController
before_filter :check_permissions, :only => [:new, :create, :cancel]
skip_before_filter :require_no_authentication
def dashboard
render "editors/dashboard.html.haml"
end
def index
#editors = Editor.all
respond_to do |format|
format.html
end
end
private
def check_permissions
authorize! :create, resource
end
end
EDIT
I noticed this Processing by Devise::RegistrationsController#create as HTML in the logs when I submit the form. I had suspected that perhaps the skip_before_filter :require_no_authentication wasn't being called, but assumed that because the EditorsController was inheriting from RegistrationController that before filter would work properly. Is that not the case?
You'll want to implement your own create method on EditorsController instead of inheriting that action from Devise::RegistrationsController. As you're seeing, the method in Devise::RegistrationsController will first check to see if you're already logged in and kick you back if you are. If you're not logged in it will create a User account and then log you in as that user.
You're trying to get around that problem with skip_before_filter :require_no_authentication, but it's likely that your form is POSTing to /editors instead of /admin/editors. So, you'll need to add a route that allows you to get to create on the EditorsController :
as :admin do
post 'admin/editors' => 'editors#create'
# your other :admin routes here
end
Then you'd want to implement a scaled down version of create. You probably want something kind of like this :
class EditorsController < Devise::RegistrationsController
def create
build_resource(sign_up_params)
if resource.save
redirect_to admin_editors_path
else
clean_up_passwords resource
respond_with resource
end
end
# your other methods here
end
You'll also want to make sure that the admin/editors/new template is pointing the form to the correct route ('admin/editors').
None of the googleable solutions worked when I tried them. This works
What I did was create a new action in the controller and a new route for it, and connect the links on my views that normally connect to create to now call my route and action.
But that wasn't enough. Because Devise is listening and will grab any add you try to do and validate it through it's own code. So instead I just add the new user record with a sql insert.
Add this route
post 'savenew', to: 'users#savenew'
Add this action to the user controller:
def savenew
rawsql = "insert into users (email, created_at,updated_at) values ('#{user_params[:email]}',now(), now())"
sql = rawsql
ActiveRecord::Base.connection.execute(sql)
redirect_to action: 'index''
end
View: new.html.erb
change the form_for so that submit will go to the new route and action, not the default Rails one.
<%= form_for User, :url => {:action => "savenew"} do |f| %>
Using Rails 4.2.6 here (my model is User instead of Editor). The following solution bypasses (I think) any devise actions that may interfere with new User creation by the admin:
Add this action to the Users controller:
def savenew
User.create_new_user(user_params)
redirect_to action: 'index'
end
Add this private method to the Users controller if it does not exist:
private
def user_params
params.require(:user).permit(:email, :password,
:password_confirmation)
end
Add this to config/routes.rb:
match '/savenew', to: 'users#savenew', via: :post
Add this class method to the User model:
def self.create_new_user(params)
#user = User.create!(params)
end
I don't have a separate Admin class in my application. Instead, I defined an admin attribute for Users and check for it with a :validate_admin before_action filter in the UsersController.
I wanted to be able to create a new user from the :index view, so I added a button:
<%= button_to 'New User', '/new_user', class: 'btn btn-primary',
method: :get %>
You might have to tweak the above solution if you have any after_create actions in the User model (e.g. sending a welcome email).
I have a custom mailer (UserMailer.rb) and a few methods to override the default Devise methods for the welcome email and forgot password emails. The mailer uses a custom template to style the emails--and it works great.
In config/initializers, I have a file with
module Devise::Models::Confirmable
# Override Devise's own method. This one is called only on user creation, not on subsequent address modifications.
def send_on_create_confirmation_instructions
UserMailer.welcome_email(self).deliver
end
...
end
(Again, UserMailer is setup and works great for the welcome email and reset password email.)
But what's not working is the option to "Resend confirmation instructions." It sends with the default Devise styling and I want it to use the styling of my mailer layout. I know I can manually add the layout to the default Devise layout, but I'd like to keep DRY in effect and not have to do that.
I've tried overriding the send_confirmation_instructions method found here, but I'm getting a wrong number of arguments (1 for 0) error in create(gem) devise-2.2.3/app/controllers/devise/confirmations_controller.rb at
7 # POST /resource/confirmation
8 def create
9 self.resource = resource_class.send_confirmation_instructions(resource_params)
In my initializer file, I'm able to get to this error by adding a new override for Devise, but I'm probably not doing this correctly:
module Devise::Models::Confirmable::ClassMethods
def send_confirmation_instructions
UserMailer.send_confirmation_instructions(self).deliver
end
end
Any ideas?
You don't have to go through that initializer to do that. I've done this by overriding the confirmations controller. My routes for devise look like:
devise_for :user, :path => '', :path_names => { :sign_in => 'login', :sign_out => 'logout', :sign_up => 'signup'},
:controllers => {
:sessions => "sessions",
:registrations => "registrations",
:confirmations => "confirmations"
}
Then, create the confirmations_controller and extend the Devise::ConfirmationsController to override:
class ConfirmationsController < Devise::ConfirmationsController
In that controller, I have a create method to override the default:
def create
#user = User.where(:email => params[:user][:email]).first
if #user && #user.confirmed_at.nil?
UserMailer.confirmation_instructions(#user).deliver
flash[:notice] = "Set a notice if you want"
redirect_to root_url
else
# ... error messaging or actions here
end
end
Obviously, in UserMailer you can specify the html/text templates that will be used to display the confirmation message. confirmation_token should be a part of the #user model, you can use that to create the URL with the correct token:
<%= link_to 'Confirm your account', confirmation_url(#user, :confirmation_token => #user.confirmation_token) %>
I have a Ruby On Rails 3.x application using device.
My goal is to add a Yubikey input field to the login screen.
I have generated the views, adjusted the screen (i.e. the extra field shows up) and updated the routes as follows:
devise_for :users, :controllers => { :sessions=>"sessions", :registrations => "registrations" }, :path => "users", :path_names => { :sign_in => "login", :sign_out => "logout", :sign_up => "register" }
Not to forget, I created a session controller:
class SessionsController < Devise::SessionsController
def create
begin
if do_some_other_checks
super
else
build_resource
clean_up_passwords(resource)
flash[:alert] = "Login error"
render :new
end
rescue => e
build_resource
clean_up_passwords(resource)
flash[:alert] = "Login error"
render :new
end
end
end
Unfortunately the code doesn't quite work, it gets called after Devise has the user logged on, i.e. even if the additional check fails, the user still gets logged in.
There is a simple way to do this in your user model by adding in the following, no need to create any devise controllers or change default routes ...
class User < ActiveRecord::Base
# check to see if a user is active or not and deny login if not
def active_for_authentication?
super && do_some_other_checks
end
end
How can I customize error messages to override devise passwords controller?
class PasswordsController < Devise::PasswordsController
def create
self.resource = resource_class.send_reset_password_instructions(params[resource_name])
if resource.errors.empty?
set_flash_message(:notice, :send_instructions) if is_navigational_format?
respond_with resource, :location => home_path
else
binding.pry
flash[:devise_password_error] = (resource.errors.map do |key, value|
value.capitalize
end).flatten.join('|')
redirect_to home_path and return
end
end
def edit
self.resource = resource_class.new
resource.reset_password_token = params[:reset_password_token]
end
end
resource.errors is available in this method but it contains default messages such as Email not found and Email can't be blank. i need to customize this messages. I've tried to remove :validatable from my user model and add custom validators but this works only for my custom registrations controller derived from Devise::RegistrationsController and not for custom passwords controller.
Is there any solution?
The answer is to modify config/locales/devise.en.yml but you must add the settings, they are not there by default.
en:
activerecord:
errors:
models:
user:
attributes:
password:
confirmation: "does not match"
too_short: "is too short (minimum is %{count} characters)"
Credit for this goes to Vimsha who answered virtually the same question for me.
Devise messages are located in config/locales/devise.en.yml
I'm not sure which message you're trying to override, but that's where you want to do that.
It's not ideal, but based on this related ticket I've got it working with the following (which I know is a bit of a hack, but it works):
module DeviseHelper
def devise_error_messages!
resource.errors.full_messages.map { |msg| msg == 'Email not found' ? 'The email address you entered could not be found. Please try again with other information.' : msg }.join('<br/>')
end
end
Put this in a module called devise_helper.rb in your /app/helpers directory
Add this to your routes.rb
devise_for :users, controllers: { passwords: 'passwords' }
or
devise_for :users, :controllers => { :passwords => 'passwords' }