Rails : i18n : unexpected redirections

In my app, I have different User types like VehicleOwner , GarageOwner, Admin and unidentified/unauthenticated. I wanted to implement localization for English and Finnish. I was successful, but suddenly all my old URLs stopped working; when I tried to access the old URLs I was redirected to login page, and the login page was also not loading – stuck on infinite redirection loop.

Continue reading

Devise: Resource specific Logic in Rails Routes : Examples

If you are willing to implement or learn how to route a particular URL request to specific controller on the basis of which role the currently logged-in user is.

# in routes.rb
authenticate :user, -> (user) { user.stylist? } do
  resources :stylist_profiles, only: [:index, :show], path: '/profile'
end

authenticate :user, -> (user) { user.customer? } do
  resources :customer_profiles, only: [:index, :show], path: '/profile'
end

The URL /profile or /profile/1 will route to StylistProfileController if user’s role is Stylist and will route to CustomerProfileController if user’s role is Customer .


condition = -> (u) {
  ['qa', 'development', 'staging'].include?(Rails.env) || (u.admin? && Rails.env.production?)
}

authenticate :user, condition do
  mount Sidekiq::Web => '/sidekiq'
  mount RedisBrowser::Web => '/redis-browser'
end

Some additional examples

# in config/routes.rb
# Home page is root for UnAuthenticated visitors
#  This shall be at the top
unauthenticated :user do
  root 'pages#home', page: 'home'
end

authenticate :user, ->(user) {user.vehicle_owner? } do
  root 'vehicle_owners/quote_requests#index'
end

authenticate :user, ->(user) {user.garage_owner? } do
  root 'garage_owners/quote_requests#index'
end
Image

OmniAuth : Doorkeeper : Devise : Redirect to the application after signup/signin

As you have an oauth provider using `Doorkeeper` and other oauth applications (clients). Its annoying when you have not already logged in to the provider app and you clicked `Sign In With Main App‘ button in the login page. Then the main app throws you at the login page. When you have to go to the login page in your client app and do the login all over again. This is so annoying.

If you want to get auto redirected to the client app after filling the sign-in form in the main app(provider app) then here is the solution

Doorkeeper.configure do
  # Change the ORM that doorkeeper will use (needs plugins)
  orm :active_record

  # This block will be called to check whether the resource owner is authenticated or not.
  resource_owner_authenticator do
    user_id = session["warden.user.user.key"][0][0] rescue nil
    User.find_by_id(user_id) || begin
      session['user_return_to'] = request.url
      redirect_to(new_user_session_url)
    end
  end
  
  ...

`begin .. end` block

In the snipped above; you have seen `begin` which might be new to you been used in such scenario.

`begin` is some how like a `do`..`end` closure however this cannot be stored in a variable.

  • its executed in the instant and binding its defined.
  • it returns the last statement executed inside it
  • returning from it returns from its container function
 > a= begin
?> 12
?> 13
?> end
 > a
 # => 13

Rails : OmniAuth : Doorkeeper : Get access to provider’s api

I assume  you have set up your own OmniAuth provider or have used Providers like Facebook, Twitter, LinkedIn.

If in some condition you need to access the api of the OAuth provider like FB’s Graph API and modifying user data in Linked in or Twitter or even in your own provider, you need to verify your authenticity to the provider.

So make sure you keep the access_token given by the provider safe somewhere in session for future use.

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def the_pact
    # You need to implement the method below in your model (e.g. app/models/user.rb)
    auth_data = request.env["omniauth.auth"]
    @user = Spree::User.from_omniauth(auth_data)
    if @user.persisted?
      set_return_to_path_for_admin if @user.is_admin?
      sign_in_and_redirect @user, :event => :authentication # this will throw if @user is not activated
      
      token = auth_data['credentials']['token']
      session['the_pact_access_token'] = token
      
      set_flash_message(:notice, :success, :kind => "ThePact") if is_navigational_format?
    else
      session["devise.the_pact_data"] = auth_data
      redirect_to new_user_registration_url
    end
  end

Then some where in controller you can use the token to use the provider’s APIs to access some external resource.

To have a token object you can simple do

class ThePact::Client < OAuth2::Client
  def initialize
    super(
        ENV['thepact_app_id'],
        ENV['thepact_secret'],
        site: ENV['oauth_provider_url'],
        parse_json: true
    )
  end
end

class ThePact::Token < OAuth2::AccessToken
  # Return a new OAuth2::AccessToken specific to the app
  # and the user with the given token.
  def initialize(token)
    super(
        ThePact::Client.new,
        token
    )
  end
end


access_token = ThePact::Token.new(session['the_pact_access_token'])
access_token.post('some/url', params: {url: 'params'}, body: {file: upload})

Note:

if you pass `params` hash then the data will be sent via URL and visible to network sniffers. If you are sending form data use `body` instead.

 

Sources:

http://stackoverflow.com/a/5698954/3437900