3

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 ('/'+@user.username)
        #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.

Community
  • 1
  • 1
Mittenchops
  • 18,633
  • 33
  • 128
  • 246

2 Answers2

3

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.

Ryan Bigg
  • 106,965
  • 23
  • 235
  • 261
  • I see. Can you explain to me what's wrong with the current controller style? How should I be thinking of the other correctly? – Mittenchops Jul 17 '12 at 01:55
  • Ryan, you've very thoroughly answered my question, but can I follow up by asking how to name a redirect route? I'm trying this, which isn't working, under my create user method: `@user = User.new(params[:user]) if @user.save redirect_to @user.username` – Mittenchops Jul 17 '12 at 15:36
  • Nevermind---for anyone else doing this, I solved it with ` redirect_to '/' + @user.username` – Mittenchops Jul 17 '12 at 17:01
  • 1
    @Mittenchops: That's quite ugly. What I would do is override to_param on the user model to return just `username` and then just `redirect_to @user` will redirect to the correct path. – Ryan Bigg Jul 17 '12 at 22:02
  • I've updated to follow your comment here---can you point me to why this isn't working? `redirect_to @user` tries to redirect to nil. – Mittenchops Jul 21 '12 at 17:48
  • @Mittenchops: It would be redirecting to nil only if you had not set `@user` yet, or purposely set it to `nil`. – Ryan Bigg Jul 23 '12 at 23:31
0

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

resources :users, :path => '/'

Mittenchops
  • 18,633
  • 33
  • 128
  • 246