Mittenchops
Mittenchops

Reputation: 19664

Correct routing for short url by username in Rails

I am trying to replace user profile views of the sort

/users/1

with

/username

I'm aware this means I'll need to check for collisions of various kinds. I've consulted the following similar SO questions:

Here are the various failed routes.rb route definitions I've tried, and associated errors:

  1. match "/:username" => "users#show", via: "get"

    Here's the error:

    ActiveRecord::RecordNotFound in UsersController#show
    
    Couldn't find User without an ID
    
    app/controllers/users_controller.rb:7:in `show'
    

    Here is my corresponding users_controller:

    6 def show
    7   @user = User.find(params[:id])
    8 end
    
  2. match "/:username" => 'users#show', :as => :profile

    Same error as above.

  3. match "/:username", :controller => "users/:id", :action => 'show'

     Routing Error
    
     uninitialized constant Users
    
     Try running rake routes for more information on available routes.
    
  4. match '/:username', :controller => 'users', :action => 'show'

    Same error as 1.

  5. match '/:username', to: 'users/:id', via: 'show'

    Server does not start.

  6. match "/:username" => redirect("/users/:id")

    Error:

     ActiveRecord::RecordNotFound in UsersController#show
    
     Couldn't find User with id=:id
    

Any idea why my routing is not working the same way that everyone else who asks this question's is?

Update

Just to take this issue out of the comments and put it in the question more cleanly. After making the change by @Ryan Bigg below, I had a routing problem in my redirect to profile when a new one is created. Here's my create code:

  def create
    @user = User.new(params[:user])
    if @user.save
        session[:user_id] = @user.id
        flash[:success] = "Thank you for signing up."
        redirect_to ('/'[email protected])
        #redirect_to @user, notice: "Thank you for signing up!"
    else
        render "new"
    end
  end

And here is my user.rb

def to_param
    self.username
    #username
end

However, the commented out redirect, which I think should work with the to_param update, doesn't work, while the ugly hackish one above it does. Why is the to_param overwrite, which worked for other people, not working on my app? My #update and #edit methods are also not working, as their redirects go to "users/1/edit" instead of "username/edit" if overwriting to_param doesn't take care of this.

Upvotes: 3

Views: 1269

Answers (2)

Mittenchops
Mittenchops

Reputation: 19664

In addition to the update for to_params, the bottom of the routes file needs the following line:

resources :users, :path => '/'

Upvotes: 0

Ryan Bigg
Ryan Bigg

Reputation: 107728

The first one is correct, but isn't working because you're still attempting to do something like this inside your controller:

User.find(params[:username])

When you should instead be doing this:

User.find_by_username!(params[:username])

The first one will attempt to find by the primary key of your table, where the second one will, correctly, query on the username field instead.

Upvotes: 3

Related Questions