I am trying make a project in which /username gets redirected to that username's profile. How can I make this happen?
The route would be: "get /:username", to: "users#profile"
You would change users#profile to whatever your controller action is called.
You need to make sure to put this at the end of your routes. Otherwise it will intercept all your routes.
For example, don't do the following:
get "/:username", to: "users#profile"
get "/foo", to: "pages#bar"
Because you will never be able to reach the pages#bar endpoint.
Problem with the previous answer is that anything that doesn't match in routes would be routed to users#profile.
Alternatively, and to solve that issue, you can create a dynamic router, like this:
class DynamicRouter
def self.load
Rails.application.routes.draw do
User.all.each do |user|
puts "Routing #{user.name}"
get "/#{user.name}", :to => "users#profile", defaults: { id: user.id }
end
end
end
def self.reload
Rails.application.routes_reloader.reload!
end
end
Then on the UsersController:
class UsersController < ApplicationController
def profile
#user = User.find(params[:id])
redirect_to not_found_path unless #user
end
end
And to actually generate the routes at server start:
Rails.application.routes.draw do
...
get 'not_found' => 'somecontroller#not_found', as: :not_found
DynamicRouter.load
end
Finally to reload routes when a user is added/updated:
class User < ActiveRecord::Base
...
after_save :reload_routes
def reload_routes
DynamicRouter.reload
end
end
Hope it helps!
Related
I'm sure this is an obvious question but I just don't understand why this isn't working.
I'm finding that my static pages defined in the routes.rb file don't seem to have access to cookies? Is that correct? I'm trying to read the value of a cookie but the pages below seem to return a null object.
My routes.rb contains the following:
scope controller: :static do
get :about
get :terms
get :privacy
get :cookies
get :returns
get :delivery
end
For completeness here is the Static Controller:
# frozen_string_literal: true
class StaticController < ApplicationController
before_action :find_order
def index; end
def about; end
def pricing
redirect_to root_path, alert: t('.no_plans') unless Plan.without_free.exists?
end
def terms; end
def privacy; end
def cookies; end
def returns; end
def delivery; end
end
And this is how the cookie is set:
class OrdersController < ApplicationController
before_action :find_order
def add_hamper
#order ||= Order.create!(
ordernum: find_next_order_number,
user: current_user,
basket: true
)
#order.hampers << Hamper.friendly.find(params[:id])
update_order_total(#order)
if current_user&.custaddress
#order.update(custaddress: current_user.custaddress)
else
cookies[:ordernum] = #order.ordernum
end
redirect_to order_path(#order.ordernum)
# Update basket in Navbar
# Save the information as a cookie reference if they are not signed in
end
At the start of each controller I have a before_action to find an order if it exists in the DB or Cookie. For all other controllers, the find_order method is working. For the StaticController, there seems to be no access to the cookies.
Here is my find_order as defined in ApplicationController:
def find_order
#order = if current_user
Order.where(
user: current_user,
basket: true
).first
else
if cookies.dig[:ordernum]
Order.where(
ordernum: cookies[:ordernum],
basket: true
).first
end
end
end
helper_method :find_order
I've had to add the check for cookies and then if cookies[:ordernum] to stop it from failing on the static pages.
Thanks for any help with this.
PS. If anyone feels the above code could be better ... please let me know! There must be a nicer way to achieve this. It feels a little clunky.
In my Rails app I want to forward my users to their personal sign in page which is stored in a cookie :user_subdomain. So when a user goes to www.app.com/sign_in, s/he should be automatically forwarded to www.app.com/sign_in/mycompany.
How can this be achieved?
I would like to keep my sign_in_path helper method because it's sprinkled all over my app.
If I simply redirect the new action using redirect_to sign_in_path(:name => cookies[:user_subdomain]) I end up in a loop.
Thanks for any pointers.
# routes.rb:
get 'sign_in', :to => 'sessions#new'
# sessions_controller.rb:
class SessionsController < ApplicationController
def new
params[:name] ||= cookies[:user_subdomain]
end
...
end
Then the solution is easy. You do not need to redirect, you just need optional parameter for your routes.
bound parameters
# routes.rb:
get 'sign_in(/:company_name)', :to => 'sessions#new'
# This will allow
# /sign_in
# and
# /sign_in/mycompany
# Both will lead to same action and you can keep your helper
# sessions_controller.rb:
class SessionsController < ApplicationController
def new
params[:company_name] ||= cookies[:user_subdomain]
# You logic here
end
...
end
I'd like to be able to set the root url in routes.rb based on the logged in/out state of Authlogic. Here is an example of what I need to do:
root :to => 'users#index', :constraints => lambda { |request| # ??? }
root :to => 'welcome#index'
get '/' => 'users#index', :as => 'user_root'
This would enable logged in users to go to users#index and logged out users to go to welcome#index without doing a redirect. I do know how to set a before_filter and redirect accordingly, but I'd rather not do that.
I know this is possible with Devise but I need to solve this for Authlogic. Similar question here without an answer.
You can create a custom route constraint pretty easily. Any object that responds to matches? can be handed to the :constraints route option. To check for Authlogic authentication, you would need to pull your Authlogic methods from your ApplicationController and put them somewhere else. I recommend using a concern for these anyways.
# app/concerns/authlogic_methods.rb
module AuthlogicHelpers
extend ActiveSupport::Concern
module InstanceMethods
private # All methods are private
def current_user_session
return #current_user_session if defined?(#current_user_session)
#current_user_session = UserSession.find
end
def current_user
return #current_user if defined?(#current_user)
#current_user = current_user_session && current_user_session.user
end
end
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
include AuthlogicHelpers
end
# config/initializers/route_constraints.rb
module RouteConstraints
class LoggedIn
include AuthlogicHelpers
def matches?(request)
current_user
end
end
end
# config/routes.rb
constraints RouteConstraints::LoggedIn.new do
root :to => 'dashboard#show'
end
Note that we're instantiating a new RouteConstraints::LoggedIn object. This is because the Authlogic methods current_user and current_user_session are defined as instance methods and create instance variables — if they aren't separated for each request, you won't be sure a user is actually logged in or another one was logged in before.
You might run into problems if Authlogic tries to access params directly. In this case, you will probably need to override the UserSession.new method to accept the request object as an argument and call request.params to get the params.
Authlogic already have the machinery native (tested against Rails 6.0 and Authlogic 6.0):
class AuthlogicSignedInConstraint
def matches?(request)
Authlogic::Session::Base.controller = Authlogic::ControllerAdapters::AbstractAdapter.new(request)
user_session = UserSession.find
user_session && user_session.user
end
end
Authlogic in recent versions require a controller object to be instantiated otherwise it can't find the session data necessary for loading a session.
In fact, contained under authlogic/controller_adapters/ are adapters for various controller implementations: Rails Controllers, Sinatra and Rack.
The interface is fairly simple, so I wrote an adapter to work with the ActionDispatch::Request that one has access to within a constraint.
This has been tested on Rails 4.2, Rails 5 should be similar.
class AuthlogicRequestAdapter
attr_reader :request
def initialize(request)
#request = request
end
def authenticate_with_http_basic
end
def cookies
request.cookies
end
def params
request.params
end
def session
_, session_hash = Rails.application.config.session_store.new(Rails.application, Rails.application.config.session_options).load_session(request.env)
session_hash
end
end
Example of use in Rails
Route Constraint
class UserRouteConstraint
def matches?(request)
Authlogic::Session::Base.controller = AuthlogicRequestAdapter.new(request)
user = UserSession.find
if user&.record.present?
true
else
false
end
end
end
routes.rb
MyRailsApp::Application.routes.draw do
# ... other routes
constraints(UserRouteContraint.new) do
root :to => 'users#index'
end
root :to => 'welcome#index'
get '/' => 'users#index', :as => 'user_root'
end
I have looked all over the place, and found a lot of info... but nothing works for me and I don't get it :(
I know that you are suppose to override the registration controller, like this:
class Users::RegistrationsController < Devise::RegistrationsController
def after_sign_up_path_for(resource)
authors_waiting_path
end
end
Then following the example showed by Tony Amoyal http://www.tonyamoyal.com/2010/07/28/rails-authentication-with-devise-and-cancan-customizing-devise-controllers/, I am supposed to change my routes to update the access the new controller:
devise_for :users, :controllers => { :registrations => "users/registrations" } do
#get '/author/sign_up', :to => 'devise/registrations#new'
#get '/client/sign_up', :to => 'devise/registrations#new'
get '/author/sign_up', :to => 'users/registrations#new'
get '/client/sign_up', :to => 'users/registrations#new'
end
Yes, I have something a bit strange here, because I am catching some specific path to send them to the registration page, this allows me to create effectively 2 registration scenario.
I commented what I had before I had overridden the registration controller.
Even with all this and my authors_waiting_path being a valid path, it just keeps on going to the sign-in page after registration :(
This is really frustrating.
Alex
edit: I also found this on the devise wiki: https://github.com/plataformatec/devise/wiki/How-To:-Redirect-after-registration-(sign-up)
But I have no idea where to define this create method ? should I override the session controller ???
edit 2:
I put a dummy override of the controller:
class Pouets::RegistrationsController < Devise::RegistrationsController
def after_sign_up_path_for(resource)
authors_waiting_path
end
def new
super
end
def create
puts "was here"
super
end
def edit
super
end
def update
super
end
def destroy
super
end
def cancel
super
end
end
And I never the "was here" in my logs.... I really have the feeling that it's totally ignoring the override... I must be doing something wrong :(
Ok... I am able to override it so you should be either :0
Create folder app/controllers/users
put there registrations_controller.rb with: (option with session - but it will try sign_in and later redirect - it may be not intended behavior for you ). Furthermore this is from devise wiki and I am not sure if it works
class Users::RegistrationsController < Devise::RegistrationsController
def create
session["#{resource_name}_return_to"] = complete_path
super
end
end
restart application (just for ensure you don't trust anything)
All in all you must override Create If you want redirect only Users... if you want define some more complex scenario you should monkeypatch sign_in_and_redirect
so your controller will looks like
class Users::RegistrationsController < Devise::RegistrationsController
# POST /resource/sign_up
def create
build_resource
if resource.save
set_flash_message :notice, :signed_up
#sign_in_and_redirect(resource_name, resource)\
#this commented line is responsible for sign in and redirection
#change to something you want..
else
clean_up_passwords(resource)
render_with_scope :new
end
end
end
second option try to monkeypatch helper ....
module Devise
module Controllers
# Those helpers are convenience methods added to ApplicationController.
module Helpers
def sign_in_and_redirect(resource_or_scope, resource=nil, skip=false)
#intended behaviour for signups
end
end
end
end
I have tried the above solution and while it works, reading devise code, I have found that all you actually need in order to sign-out just registered user and redirect is:
to add is_approved or similar to your user table and
to add active_for_authentication? method in your User model
Code:
class User < ActiveRecord::Base
# ... some code
def active_for_authentication?
super && is_approved
end
end
Was a bit hard to find when I needed it, but that is all. I am actually writing it here in case someone else needs it.
How can I have make auto redirecting every user who goes to mysite.com/ to mysite.com/features?
thanks
Set your root route to direct folks there (these are Rails 3 routes):
in config/routes.rb
root "content#features"
in app/controllers/contents_controller.rb
class ContentsController < ApplicationController
def features
end
end
That won't do a redirect, however. To do that, you'll need something like this:
in config/routes.rb
match "features" => "contents#features", :as => "features"
root "content#index"
in app/controllers/contents_controller.rb
class ContentsController < ApplicationController
def index
redirect_to features_url
end
def features
end
end