How to access current_account in models in Padrino? - ruby

I'm working on a Padrino application that has a main App and an Admin app. When a user logins through session, I just run the following two lines to log him in.
account = Account.authenticate(params[:email], params[:password])
set_current_account(account)
With debugger in any controllers in Admin
current_account
#<Account #id=1 #name="John" #surname="Davies" #email="john.davies#gmail.com" #crypted_password="3456789" #role="admin">
With debugger in any models
current_account
*** NameError Exception: undefined local variable or method `current_account' for #<Post #id=1 #question="Why is this not working?" #answer="I have no idea">
I am able to access current_account to find out which user is logged in in the Admin app, but this variable is not accessible in the main App.
What I am trying to do is that I am creating an Activity Feed, or Audit Trail, for all my models, so when a record is created/updated/destroyed in any model, a new record is created in model Activity. That being said, I need to access the current_account variable in my models.
I have searched for solutions, and came across a suggestion:
In admin/app.rb
enable :sessions
set :session_id, "my-global-session"
In app/app.rb
register Padrino::Admin::AccessControl
register Padrino::Admin::Helpers
enable :sessions
set :session_id, "my-global-session"
It did not work for me. Is there a way I can access current_account in my models?
Thank you for any guide or suggestion.

I'm not exactly sure what are you trying to do, but I solved a similar problem like this:
class Account
# ...
class << self
attr_accessor :current
end
# ...
end
class Admin < Padrino::Application
#...
before do
Account.current = current_account
end
# ...
end
And then use Account.current to access it.

Related

Welcome emails in Ruby

I'm using Ruby and Devise:Confirmable. A day or so after a new user has registered and confirmed a new trial account we'd like to automatically send him or her a 'follow up email'. Is this something we should also do through devise, or is there a separate gem or process we should implement?
Since you are using Devise already, you can just overwrite the confirmation controller, try something like this.
class ConfirmationsController < Devise::ConfirmationsController
# GET /resource/confirmation?confirmation_token=abcdef
def show
super do |resource|
YourMailerClass.follow_up(resource).deliver_later(wait_until: 1.day.from_now) if resource.errors.empty?
end
end
end
You also need to update the routes.rb file, add the option controllers: { confirmations: :confirmations } at the end of the line where you define devise_for (restart your server after this).
I'm assuming you already have a background jobs proccesor, like sidekiq
Hope it helps

How to allow access only to logged in users restricting direct entry of url?

in a Rubyonrails application i want only logged in users to enterinto the inner pages?
how can i redirect the direct entered urls to index page?
in php if(!isset($_SESSION[id]) { header("location:index.php") }, how this can be implemented in ruby on rails
here goes
In application_controller.rb:
Putting this code in application_controller will make it available to all your controllers.
class ApplicationController < ActionController::Base
protect_from_forgery
protected
def confirm_logged_in
unless session[:id]
flash[:notice] = "Please log in"
redirect_to :root
return false
else
return true
end
end
end
Then you can make use of this method in any of the controllers that require it, for eg
If you need to confirm that users are logged in for the show action, then
class UsersController < ApplicationController
before_filter :confirm_logged_in, :only => [:show]
def show
#all your code
end
end
should work, as this will confirm that users accessing this show url have logged in.
For more info checkout this link to rails guides on filters. There could be more efficient ways of achieving this as well.
However, i would suggest using a gem like Cancan (Github) as i have used this in many apps and works well. The code presented above is basic and there are many better and advanced ways to handle this but it should do the job.Hope it helps.

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

What is a very simple authentication scheme for Sinatra/Rack

I am busy porting a very small web app from ASP.NET MVC 2 to Ruby/Sinatra.
In the MVC app, FormsAuthentication.SetAuthCookie was being used to set a persistent cookie when the users login was validated correctly against the database.
I was wondering what the equivalent of Forms Authentication would be in Sinatra? All the authentication frameworks seem very bulky and not really what I'm looking for.
Here is a very simple authentication scheme for Sinatra.
I’ll explain how it works below.
class App < Sinatra::Base
set :sessions => true
register do
def auth (type)
condition do
redirect "/login" unless send("is_#{type}?")
end
end
end
helpers do
def is_user?
#user != nil
end
end
before do
#user = User.get(session[:user_id])
end
get "/" do
"Hello, anonymous."
end
get "/protected", :auth => :user do
"Hello, #{#user.name}."
end
post "/login" do
session[:user_id] = User.authenticate(params).id
end
get "/logout" do
session[:user_id] = nil
end
end
For any route you want to protect, add the :auth => :user condition to it, as in the /protected example above. That will call the auth method, which adds a condition to the route via condition.
The condition calls the is_user? method, which has been defined as a helper. The method should return true or false depending on whether the session contains a valid account id. (Calling helpers dynamically like this makes it simple to add other types of users with different privileges.)
Finally, the before handler sets up a #user instance variable for every request for things like displaying the user’s name at the top of each page. You can also use the is_user? helper in your views to determine if the user is logged in.
Todd's answer does not work for me, and I found an even simpler solution for one-off dead simple authentication in Sinatra's FAQ:
require 'rubygems'
require 'sinatra'
use Rack::Auth::Basic, "Restricted Area" do |username, password|
[username, password] == ['admin', 'admin']
end
get '/' do
"You're welcome"
end
I thought I would share it just in case anyone wandered this question and needed a non-persistent solution.
I' have found this tutorial and repository with a full example, its working fine for me
https://sklise.com/2013/03/08/sinatra-warden-auth/
https://github.com/sklise/sinatra-warden-example
I used the accepted answer for an app that just had 2 passwords, one for users and one for admins. I just made a login form that takes a password(or pin) and compared that to one that I had set in sinatra's settings (one for admin, one for user). Then I set the session[:current_user] to either admin or user according to which password the user entered and authorized accordingly. I didn't even need a user model. I did have to do something like this:
use Rack::Session::Cookie, :key => 'rack.session',
:domain => 'foo.com',
:path => '/',
:expire_after => 2592000, # In seconds
:secret => 'change_me'
As mentioned in the sinatra documentation to get the session to persist in chrome. With that added to my main file, they persist as expected.
I found JWT to be the simple, modern/secure solution I was searching for. OP mentioned bulky frameworks, so for reference I downloaded the tag of the latest jwt gem at the time of writing (2.2.3) and it's 73 KB zipped and 191 KB unzipped. Seems to be well-maintained and open sourced on GitHub.
Here's a good blog post about it with code and a walkthrough for near-beginners: https://auth0.com/blog/ruby-authentication-secure-rack-apps-with-jwt/

Resources