Правильная маршрутизация для короткого URL по имени пользователя в Rails

Я пытаюсь заменить вид профиля пользователя такого рода

/users/1

с

/username

Я знаю, что это означает, что мне нужно будет проверять наличие столкновений разных типов. Я консультировался со следующими подобными вопросами SO:

Вот различные неудачные определения маршрутов route.rb, которые я пробовал, и связанные с ними ошибки:

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

    Вот ошибка:

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

    Вот мой соответствующий users_controller:

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

    Та же ошибка, что и выше.

  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'

    Та же ошибка, что и 1.

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

    Сервер не запускается.

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

    Ошибка:

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

Любая идея, почему моя маршрутизация не работает так же, как все остальные, кто задает этот вопрос?

Обновить

Просто чтобы убрать эту проблему из комментариев и поставить ее в вопросе более четко. После внесения изменений @Ryan Bigg ниже, у меня возникла проблема с маршрутизацией при перенаправлении в профиль при создании нового. Вот мой код создания:

  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

А вот и мой user.rb

def to_param
    self.username
    #username
end

Тем не менее, закомментированное перенаправление, которое, как мне кажется, должно работать с обновлением to_param, не работает, в то время как уродливый хакер, приведенный выше, работает. Почему перезапись to_param, которая работала для других людей, не работает в моем приложении? Мои методы #update и #edit также не работают, так как их перенаправления переходят в "users/1/edit" вместо "username/edit", если перезапись to_param не позаботится об этом.

2 ответа

Решение

Первый - правильный, но не работает, потому что вы все еще пытаетесь сделать что-то подобное в вашем контроллере:

User.find(params[:username])

Когда вы должны вместо этого делать это:

User.find_by_username!(params[:username])

Первый попытается найти по первичному ключу вашей таблицы, а второй вместо этого будет правильно запрашивать поле имени пользователя.

В дополнение к обновлению to_params, нижней части файла маршрутов нужна следующая строка:

resources :users, :path => '/'

Другие вопросы по тегам