0

我让我的 Rails 应用程序运行 OmniAuth-identity,以“用户”模型保存用户。访问用户需要指向:

0.0.0.0:3000/users/:id

但我想通过输入用户的唯一名称来到达那里,例如 facebook 或 twitter:

0.0.0.0:3000/username

所以我创建了一个全球路线:

match "/*id" => "users#show"

并根据传递的参数修改了用户控制器的显示方法以按名称而不是 ID 查找:

def show
    if params[:id].is_a?(String)
      @user = User.find_by_name(params[:id])
    else
      @user = User.find(params[:id])
    end
    respond_to do |format|
      format.html # show.html.erb
      format.json { render json: @user }
    end
  end

路由工作,如果我去

0.0.0.0:3000/username

它成功显示了用户信息。但是像旧路由一样注销或查找用户不起作用..(即使我添加到控制器中的条件是检查 String||Int.

做这些事情时,我得到:

NoMethodError in Users#show

Showing /home/juanchi/Dropbox/GitHub/RSandBox/app/views/users/show.html.erb where line #5 raised:

undefined method `provider' for nil:NilClass
Extracted source (around line #5):

2: 
3: <p>
4:   <b>Provider:</b>
5:   <%= @user.provider %>
6: </p>
7: 
8: <p>
Rails.root: /home/juanchi/Dropbox/GitHub/RSandBox

Application Trace | Framework Trace | Full Trace
app/views/users/show.html.erb:5:in `_app_views_users_show_html_erb___448583227_80374500'
app/controllers/users_controller.rb:22:in `show'
Request

Parameters:

{"id"=>"logout"}
Show session dump

Show env dump

Response

Headers:

None

在用户控制器的 show 方法中获取信息失败。但是当使用新路线时它会很好......那么它缺少什么?

如何同时支持我的新路由规则和旧路由规则?

该路由与用户注销方法有什么关系?

注销时它会调用 session#detroy 方法:

def destroy
    session[:user_id] = nil
    redirect_to root_url, :notice => "Goodbye!"
  end
4

1 回答 1

1

我不确定我是否明白了这个想法,但我认为您不需要使用全局路由。

你可以使用这样的东西:

get "users/:id" => "users#show"
get ":username" => "users#show"

在您的操作中,您可以检查参数是否存在:

def show
  if params[:id].present?
    @user = User.find(params[:id])
  elsif params[:username].present?
    @user = User.find_by_name(params[:username])
  end
end

像在代码中那样检查参数的类型是没有意义的,因为它总是 String (或者 NilClass,如果它是 nil)。

还有一件重要的事情 - 路由是有序的,因此您必须get ":username" ...在路由表的末尾放置您的某个位置,以防止与 /logout、/login 等标准操作发生冲突。

实际上,要完全消除这些冲突并不容易 - 假设您的用户选择了名称“注销”。因此,您必须添加另一个逻辑来阻止用户使用此类名称。

Update: I forgot to explain why I think that globbing is not necessary - you need globbing to catch things like "foo/bar", "something/nice/in/rails" with one rule match "*xxx"

于 2012-09-11T22:11:17.543 回答