Search code examples
ruby-on-railsruby-on-rails-4activerecordroutesfriendly-id

Rails route masking


I have a rails app where I have a userpage. Each userpage is a dashboard for a user showing his listings and his activities. I am also using a User model which is coming from devise so I can't use user/:id to refer to a user as that is used for registrations and editing passwords etc.

I added a custom route as follows:

match '/userpage', to: 'listings#userpage', via: :get

The URL looks like: http://localhost:3000/userpage?id=2

My questions are:

  1. I want the url to look like http://localhost:3000/userpage/2 without creating a seperate userpage resource. How should I proceed with this? If I add match '/userpage/:id', to: 'listings#userpage', via: :get its not giving me a name for the path. I mean there is no userpage_path to access in routes.I need that userpage_path to refer it at links to the userpage.
  2. I want to show the users name instead of user_id. Right now I am showing it as: http://localhost:3000/userpage?id=2&name=CoolShop but I would want it to be http://localhost:3000/userpage/CoolShop. I know that friendly_id gem can help me out but that will need a userpage model.

Keep in mind that userpage is just a users page with his details other than his registration details provided by devise so I don't want to create a seperate model for this.


Solution

  • In the routes file (routes.rb) you should add resources :users if you don't have it already, it will add a user/:id as a user_path. (and the rest of the routes as resources usually do)

    devise doesn't have any route that conflict with that one, here is a list of the routes it adds: (when using the devise_for :users in the routes.rb file - and it depends on which modules you use)

    #  # Session routes for Authenticatable (default)
    #       new_user_session GET    /users/sign_in                    {controller:"devise/sessions", action:"new"}
    #           user_session POST   /users/sign_in                    {controller:"devise/sessions", action:"create"}
    #   destroy_user_session DELETE /users/sign_out                   {controller:"devise/sessions", action:"destroy"}
    #
    #  # Password routes for Recoverable, if User model has :recoverable configured
    #      new_user_password GET    /users/password/new(.:format)     {controller:"devise/passwords", action:"new"}
    #     edit_user_password GET    /users/password/edit(.:format)    {controller:"devise/passwords", action:"edit"}
    #          user_password PUT    /users/password(.:format)         {controller:"devise/passwords", action:"update"}
    #                        POST   /users/password(.:format)         {controller:"devise/passwords", action:"create"}
    #
    #  # Confirmation routes for Confirmable, if User model has :confirmable configured
    #  new_user_confirmation GET    /users/confirmation/new(.:format) {controller:"devise/confirmations", action:"new"}
    #      user_confirmation GET    /users/confirmation(.:format)     {controller:"devise/confirmations", action:"show"}
    #                        POST   /users/confirmation(.:format)     {controller:"devise/confirmations", action:"create"}
    

    About naming the route:

    You have added the routes just fine, but if you want to name it you should add as: "userpage" - this will add a userpage_path as you wanted.

    get  '/userpage/:id', to: 'listings#userpage', as: "userpage"
    

    or

    match '/userpage/:id', to: 'listings#userpage', via: :get, as: "userpage"
    

    About using usernames in routes instead of user id:

    using the friendly_id gem is a good idea.

    Basically, you add a new field to the users table called slug (and add an index on that field) -> then when a user registers you fill that slug field with the username. (doing: username.parameterize to swap spaces with dashes)

    And then when someone is going to /users/some-user-name you can query using the slug field instead of the id field.

    User.where(slug: params[:id]) # will get user with slug: some-user-name
    

    the gem is helping you doing that much easier.

    and you don't need a new model for that.