I'm trying to achieve that when a user deletes his account, all his activities gets also deleted.
I'm on Rails 4 - Devise - Public Activity
My Registrations Controller:
class RegistrationsController < Devise::RegistrationsController
# DELETE /resource
def destroy
resource.destroy
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
set_flash_message :notice, :destroyed if is_flashing_format?
yield resource if block_given?
respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) }
end
end
To Destroy the comments record after a user deleted his comment i used:
#activity = PublicActivity::Activity.find_by_trackable_id(params[:id])
#activity.destroy
I'm searching for something similar, only to destroy all activities after account cancelation.
Anyone a good Solution ?
in User.rb add a callback:
before_destroy :delete_activities
def delete_activities
acts = PublicActivity::Activity.where(owner_id: self.id, owner_type: "User")
acts.delete_all
end
Related
I'm using devise to manage authentication. I have a User model and Admin model. I want to be able to allow both users and admins soft delete user accounts.
I have implemented the soft delete for users and everything works well, however, adding functionality for admins results in a 401 unauthorized and a redirect to the user sign in page. I'm not exactly sure how to get around this.
So far I have:
config/routes.rb
...
devise_for :users
devise_scope :user do
resources :users, only: [:destroy], controller: 'members/registrations', as: :user_registration do
get 'cancel'
end
end
...
controllers/members/registrations_controller.rb
class Members::RegistrationsController < Devise::RegistrationsController
def destroy
#user = User.find(params[:id])
not_authorized unless authorized?
#user.soft_delete
user_post_destroy if is_current_user?
end
private
def authorized?
if signed_in?
is_current_user?
else
session[:session_id] == #user.author_session_token
end
end
def not_authorized
flash[:error] = t('errors.messages.not_authorized')
flash.keep
redirect_back(fallback_location: root_path)
end
def user_post_destroy
Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name)
set_flash_message :notice, :destroyed
yield resource if block_given?
respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) }
end
def is_current_user?
#user == current_user
end
end
models/user.rb
...
def soft_delete
update_attribute(:deleted_at, Time.current)
end
def active_for_authentication?
super && !deleted_at
end
def inactive_message
!deleted_at ? super : :deleted_account
end
...
I'm trying to figure out how to use wisper with Devise.
When a new user account is registered, I want to create some sample data for that user.
So in my user model I would have:
include Wisper::Publisher
after_create :notify
def notify
publish(:user_created, self)
end
and my listener would be something like:
class SampleDataCreator
def user_created(user)
user.widgets.create!(name: "Your First Widget")
end
end
But I can't figure out how to tie this into Devise. How can I configure the SampleDataCreator to listen for events from the Devise user model?
UPDATE
I've tried attaching the listener in the Devise registration controller as follows:
class RegistrationsController < Devise::RegistrationsController
def create
super do |resource|
resource.subscribe(SampleDataCreator.new)
end
end
end
but it seems the listener never gets triggered.
UPDATE 2
I realised the above approach wasn't working because the record is saved before yield is called. It seems tricky to hook into Devise before this point, so instead I overrode the whole method:
def create
build_resource(sign_up_params)
resource_saved = resource.save
yield resource if block_given?
resource.subscribe(SampleDataCreator.new) # <-------------------- my addition
if resource_saved
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_flashing_format?
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
respond_with resource
end
end
This now works, although it's not very elegant.
UPDATE 3
I found a much simpler way, I can just hook into build_resource:
class RegistrationsController < Devise::RegistrationsController
def build_resource(sign_up_params)
super.subscribe(SampleDataCreator.new)
end
end
I would subscribe the SampleDataCreator globally.
I saw a complex project where the listeners were unsubscribing and subscribing all the times. It was almost chaotic. I would recommend to avoid the subscribe/unsubsribe dynamics.
I need to convert this code in my ConfirmationsController to work in Rails 4. I'm having difficulty with the requirements for Strong Parameters. The code I'm using is directly from the Devise page
I'm pretty sure that anything I am calling with params needs to be whitelisted but I can't quite figure out how to do that in this case. What is the best way to accomplish this.
class ConfirmationsController < Devise::ConfirmationsController
def show
self.resource = resource_class.find_by_confirmation_token(params[:confirmation_token]) if params[:confirmation_token].present?
super if resource.nil? or resource.confirmed?
end
def confirm
self.resource = resource_class.find_by_confirmation_token(params[resource_name][:confirmation_token]) if params[resource_name][:confirmation_token].present?
if resource.update_attributes(params[resource_name].except(:confirmation_token).permit(:password, :password_confirmation)) && resource.password_match?
self.resource = resource_class.confirm_by_token(params[resource_name][:confirmation_token])
set_flash_message :notice, :confirmed
sign_in_and_redirect(resource_name, resource)
else
render action: "show"
end
end
end
Try this:
class ConfirmationsController < Devise::ConfirmationsController
def show
self.resource = resource_class.find_by_confirmation_token(confirmation_token) if confirmation_token.present?
super if resource.nil? or resource.confirmed?
end
def confirm
self.resource = resource_class.find_by_confirmation_token(confirmation_token) if confirmation_token.present?
if resource.update_attributes(resource_params) && resource.password_match?
self.resource = resource_class.confirm_by_token(confirmation_token)
set_flash_message :notice, :confirmed
sign_in_and_redirect(resource_name, resource)
else
render action: "show"
end
end
private
def resource_params
# pry
# debugger
params.require(resource_name).permit :password, :password_confirmation
end
def confirmation_token
params.require(resource_name).permit :confirmation_token
end
end
More info: https://github.com/rails/strong_parameters
If you continue having trouble I'd recommend stuffing a debugger or pry in the middle and manipulating the params with permit | require until you have what you'd expect.
I have a bunch of code that hands over stuff from a logged in user's guest/lazy registered account to his new account which I run when a new session is created.
class SessionsController < Devise::SessionsController
def new
super
end
def create
super
logging_in # this is the method which will run
end
def destroy
super
end
end
It works when the user logs in. However when Devise logs a user in after confirmation, the above does not get run. Where should I put the method if I want it to run after a user logs in? whether by logging in or confirmation.
Thanks nash. Here's how I did it.
class ConfirmationsController < Devise::ConfirmationsController
def new
super
end
def create
super
end
def show
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
if resource.errors.empty?
set_flash_message(:notice, :confirmed) if is_navigational_format?
sign_in(resource_name, resource)
logging_in # Here it is
respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
else
respond_with_navigational(resource.errors, :status => :unprocessable_entity){ render :new }
end
end
protected
def after_resending_confirmation_instructions_path_for(resource_name)
new_session_path(resource_name)
end
def after_confirmation_path_for(resource_name, resource)
after_sign_in_path_for(resource)
end
end
It needs to be added after sign_in because my logging_in method uses current_user.
I'm trying to redirect users that have failed the sign up form (e.g. they entered a username that is already taken, they left a field blank, etc...)
I have custom failure set up for users that fail the sign in form, code below:
class CustomFailure < Devise::FailureApp
def redirect_url
root_path
end
def respond
if http_auth?
http_auth
else
redirect
end
end
However, I've been stuck on how to set this up for sign up failure. Ideally I would just like to redirect them back/to root_path, any ideas? Thank you!
You will probably need to subclass Devise::RegistrationsController and override the create action. Just copy over the create method from here and modify the redirect on failure to save.
# app/controllers/registrations_controller.rb
class RegistrationsController < Devise::RegistrationsController
def create
# modify logic to redirect to root url
end
end
Change your routes to tell Devise to use your controller:
# config/routes.rb
devise_for :users, :controllers => {:registrations => "registrations"}
It's a bit tedious to modify certain parts of devise to suit your needs and I suspect it's because the gem does a good job to cover most common cases. However, edge-cases for use of devise are a lot and your question points to one of them. I had to do something similar, that is, make sure devise redirects to a specific page when a user does one of the following:
submits form on an empty form
submits an already existing email.
Below is how I handled it.
First, create a controller called RegistrationsController that inherits from Devise::RegistrationsController like so:
class RegistrationsController < Devise::RegistrationsController
end
Inside this controller you will have override the create method in devise. Go to the devise github page here, https://github.com/plataformatec/devise/blob/master/app/controllers/devise/registrations_controller.rb to view the create method and copy the code in that method. Then create a private method to override the returning statment of the last block of the if statement. Your controller should look like so,
class RegistrationsController < Devise::RegistrationsController
def create
build_resource(sign_up_params)
resource.save
yield resource if block_given?
if resource.persisted?
if resource.active_for_authentication?
set_flash_message! :notice, :signed_up
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message! :notice, :"signed_up_but_#{resource.inactive_message}"
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
set_minimum_password_length
response_to_sign_up_failure resource
end
end
private
def response_to_sign_up_failure(resource)
if resource.email == "" && resource.password == nil
redirect_to root_path, alert: "Please fill in the form"
elsif User.pluck(:email).include? resource.email
redirect_to root_path, alert: "email already exists"
end
end
end
It should work.
Tip:
To keep flash error messages add this line before the redirect_to in your override
resource.errors.full_messages.each {|x| flash[x] = x}
So in your registrations_controller.rb :
def create
build_resource(sign_up_params)
if resource.save
yield resource if block_given?
if resource.active_for_authentication?
set_flash_message :notice, :signed_up if is_flashing_format?
sign_up(resource_name, resource)
respond_with resource, location: after_sign_up_path_for(resource)
else
set_flash_message :notice, :"signed_up_but_#{resource.inactive_message}" if is_flashing_format?
expire_data_after_sign_in!
respond_with resource, location: after_inactive_sign_up_path_for(resource)
end
else
clean_up_passwords resource
resource.errors.full_messages.each {|x| flash[x] = x} # Rails 4 simple way
redirect_to root_path
end
end
In config/routes.rb:
devise_scope :user do
get '/users', to: 'devise/registrations#new'
end