Adding a flash after authentication with merb-auth - ruby

What's the best way to add a flash message, for successful or unsuccessful login when using the merb-auth slice (Other than overriding sessions create)?

Hey deimos. If you want to add an message without overwriting the create action you can always use an after filter. Something like
...........
after :set_login_flash, :only => [:create]
private
def set_login_flash
flash[:error] = "You're not logged in" unless logged_in?
end
..........
You'll need to tune it to use the appropriate flash system that you're using in your application but something like that should work for you.

Related

Rails: Flash messages doesn't clear until it is read/accessed

I set the flash message as below in one of my routes
def signup
flash[:is_signup] = true
... redirect_to route1 : route2 // based on some logic, redirect accordingly
end
def route1
// access flash[:is_signup]
flash.discard(:is_signup)
// do something
end
As depicted above, after i set the flash variable, i could redirect_to either the route(route1) that uses this flash variable or another route(route2) that doesn't care about this flash variable at all.
The issue is, when i redirect to route2, and then go on and mind my own business, hitting several routes/actions in the process, when i end up hitting the route1, the flash variable is still there.
I haven't seen anything in the documentation that says it is available until it is read. Is this the case? or am i doing something wrong?
Thanks in Advance
I'm seeing this as well (rails 4.2.11), and agree: no docs indicate access of flash should be necessary.
But, if I have a page that sets flash[:blah] = 'applesauce' and consumes the flash (e.g., puts flash[:blah]) on the next request, that key is not present in the following request. If I don't, it will linger through request after request until I hit a one where I check the flash.
My workaround is this:
In application_controller.rb
class ApplicationController < ActionController::Base
before_action :touch_flash
#...
def touch_flash
flash
end
end
This act of referencing flash appears to be enough to trigger a discard at end of the request (but doesn't interfere with any actual access later in the request). Next request, it's gone as expected.

Validation & External APIs - Rescue in Controller or Fatten Model validations?

I am using Restforce to query records from a remote salesforce instance. The user simply has to put in a valid UID for the record they want to query.
Restforce uses Faraday middleware to deal with http requests - and raises a Faraday::ResourceNotFound error if I request something that cannot be located in the remote salesforce database.
Question
Where should I validate user input?
I have two ideas but i'm not sure of the consequences to each... and I'm trying to work out how to stick best to the fat model - skinny controller best practice.
Check for successful query at the application controller level
Requests save the UID to a simple ActiveRecord model #record_request. My create method can fire a query, check for an error and flash/redirect the user if needed.
# app/controllers/record_requests_controller
def create
#record_request = current_user.record_requests.new(record_request_params)
# Check to see if CHAIN number exists
if #record_request.restforce.find("Contact", #record_request.chain_number, 'ClientID__c')
# If it gets past that do standard validation checks
if #record_request.save
flash[:success] = 'Record request was successfully created.'
redirect_to record_requests_path
else
render :new
end
end
end
Then over in the ApplicationController I've got a rescue method setup
# app/controllers/application_controller
rescue_from Faraday::ResourceNotFound, with: :resource_not_found
private
def resource_not_found
flash[:alert] = 'Cannot find resource on Salesforce'
redirect_to(:back)
end
This works! And seems fine... but...
Model level validation?
My gut tells me this is a validation and should be validated on the model level, what if there's a bug and something sneaks into my database? Should this all just be checked at the if #record_request.save moment?
If so... how would i get model level code to handle validation AND be able to fire off an external (OAuth authenticated) API request without breaking the MVC.
What are the implications to either, and how might I do better?
I think the best way to use model level validation something like this:
validate :something
def something
errors.add(:field, 'error message') unless RestClient.check_something
end
Where RestClient is singleton object in /lib folder. This will allow to keep controller clean.

Devise: Is it possible to NOT send a confirmation email in specific cases ? (even when confirmable is active)

Here is my situation, I use devise to allow users to create account on
my site and manage their authentication.
During the registration process I allow customers to change some
options, leading to an actually different account being created but
still based on the same core user resource.
I would like to choose not to send a confirmation email for some of
those account types. I don't care if the account do not get confirmed
and user cannot log in, that's ok, no pb with that.
How would I go about doing that ?
Thanks,
Alex
Actually it's quite easy once I dig a little deeper.
Just override one method in your User model (or whatever you are using):
# Callback to overwrite if confirmation is required or not.
def confirmation_required?
!confirmed?
end
Put your conditions and job's done !
Alex
If you just want to skip sending the email but not doing confirmation, use:
# Skips sending the confirmation/reconfirmation notification email after_create/after_update. Unlike
# #skip_confirmation!, record still requires confirmation.
#user.skip_confirmation_notification!
If you don't want to call this in your model with a callback overwrite this method:
def send_confirmation_notification?
false
end
You can also simply add the following line of code in your controller before creating the new user:
#user.skip_confirmation!
I don't know if Devise added this after the other answers were submitted, but the code for this is right there in confirmable.rb:
# If you don't want confirmation to be sent on create, neither a code
# to be generated, call skip_confirmation!
def skip_confirmation!
self.confirmed_at = Time.now
end
I was able to do something similar with the functions:
registrations_controller.rb
def build_resource(*args)
super
if session[:omniauth] # TODO -- what about the case where they have a session, but are not logged in?
#user.apply_omniauth(session[:omniauth])
#user.mark_as_confirmed # we don't need to confirm the account if they are using external authentication
# #user.valid?
end
end
And then in my user model:
user.rb
def mark_as_confirmed
self.confirmation_token = nil
self.confirmed_at = Time.now
end

Can I execute custom actions after successful sign in with Devise?

I have an app that has basic Devise authentication. After sign in, I would like to look up the user account (user belongs_to account, account has_many users), and store that in the session so that it is available like the #current_user.
What is the rails way of storing session in formation like this?
Is there a hook I can use with Devise to execute code after successful sign-in?
Actually, the accepted answer does not work properly in case of combined Omniauth and Database login modules in Devise.
The native hook that is executed after every successfull sign in action in Devise (disregarding the user authentication channel) is warden.set_user (called by devise sign_in helper: http://www.rubydoc.info/github/plataformatec/devise/Devise/Controllers/SignInOut#sign_in-instance_method).
In order to execute custom action after successfull user sign in (according to Warden Docs: https://github.com/hassox/warden/wiki/Callbacks), put this into initializer (eg. after_sign_in.rb in config/initializers)
Warden::Manager.after_set_user except: :fetch do |user, auth, opts|
#your custom code
end
Update 2015-04-30: Thanks to #seanlinsley suggestion (see comments below), I have corrected the answer to include except: :fetch in order to trigger the callback only when user is authenticated and not every time it is set.
Update 2018-12-27 Thanks to #thesecretmaster for pointing out that Warden now has built-in callbacks for executing your own code on after_authentication https://github.com/wardencommunity/warden/wiki/Callbacks#after_authentication
Edit: Please consider that this was once a good solution, but there are probably better ways of handling this. I am only leaving it here to give people another option and to preserve history, please do not downvote.
Yes, you can do this. The first resource I'd look at is http://github.com/plataformatec/devise/wiki/How-To:-Redirect-to-a-specific-page-on-successful-sign-in. Also, check out How to redirect to a specific page on successful sign up using rails devise gem? for some ideas.
You can do something like:
def after_sign_in_path_for(resource_or_scope)
session[:my_account] = current_user.account
profile_url
end
You can implement this method in your ApplicationController or in a custom RegistrationsController.
i'm using rails 5 and devise 4.2.1, my solution is overide devise function on user model:
def after_database_authentication
# here's the custom code
end
and the user model will look like this:
class User < ApplicationRecord
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:timeoutable, :lockable
def after_database_authentication
# here's the custom code
end
end
it was called just after the authentication,
i read it from this devise documentation, hope this could help
I resolved this problem by overriding the create method of the session controller like following
class Admin::SessionsController < Devise::SessionsController
def create
super
# here goes my code
# my settings, etc
# do something with current_admin.fullname, for example
end
end
In other words, if authentication is successful (by calling super) then I perform my settings.
In application controller, you can simply add an after action.
app/controllers/users/application_controller.rb
class ApplicationController < ActionController::Base
after_action :do_something
def do_something
# do something
end
end

Acts_as_Inviteable Plugin not sending out invites in Ruby on Rails

I have been trying to create beta invites that each existing user can send out and was hoping to be able to use a plugin called acts_as_inviteable http://github.com/brianjlandau/acts_as_inviteable
I was wondering if anyone had direct experience with it. When I checked the console, it appears to be creating the right queries, but no email or email related errors come up.
I am tempted to just use Ryan Bates' excellent tutorial on beta invites and write it up myself, but I'd love to have something working. We just can't seem to figure it out.
There's a number of problems you need to fix:
Add this line to one of your config blocks (either in environment.rb or each of the files in config/environment):
config.action_mailer.default_url_options = {:host => 'somewhere.com'}
In app/models/invitation.rb on line 3 you have call attr_accessible :recipient_email this will prevent you from mass assigning the sender. You should change it to this:
attr_accessible :recipient_email, :sender, :sender_id
Also invitations_controller.rb should look like this:
class InvitationsController < ApplicationController
before_filter :require_analyst
def new
#invitation = Invitation.new
end
def create
#invitation = Invitation.new(params[:invitation])
#invitation.sender = current_analyst
if #invitation.save
flash[:notice] = "Thank you, invitation sent."
redirect_to root_url
else
render :action => 'new'
end
end
end
You really can't send an invitation unless you're logged in (because you need a sender, which in this case is an current_analyst not #current_user), so the lines having different logic depending on being logged in or not has been removed.
Also, the email will be automatically sent by the Invitation model so calling Mailer.deliver_invitation(#invitation, signup_url(#invitation.token)) is unnecessary (and actually it would have to be AnalystInvitationMailer.deliver_invitation(#invitation))
You can see a full working patch here: http://gist.github.com/290911

Resources