Rails 语法中的古怪 Ruby

Quirky Ruby on Rails Syntax

背景:新手 rails 开发人员在这里学习 Michael Hartl 的 Ruby Rails 教程 (https://www.railstutorial.org/),在该教程中,您开发了一个基本的类似 Twitter 的应用程序用户模型和 Post 模型。用户路由是根据我的理解生成的,这是将以下内容插入 routes.rb 文件的常用方法:

resources :users

问题:我不明白你为什么使用:

redirect_to @user

rails 将该请求发送给 UsersController#show,但它通过以下方式调用 user_url(@user) 来实现:

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

上面代码中 user_url 中的单数 ("user") 是从哪里来的?我认为 user-url 应该是 users_url 或 users_path (正如我在某些地方看到的那样)。只是想弄清楚这个单数编码到 rails.

的位置

谢谢!

欢迎来到 rails。

如果您查看所有路线,您可能会立即注意到为什么会发生这种情况。但是由于设计添加了许多额外的路由,这也可能会造成混淆。

Rail 的路由使用复数和单数模型的概念。

假设您有一个用户,路径是单一的 -- user_path(@user) - 并且 url 将是 /users/1

如果您想查看所有用户的集合,路径是复数 -- users_path -- 并且 URL 将是 /users

与该用户相关的所有路由也是如此。当您谈论仅影响单个对象的动作时,路径是单数,而影响多个对象的动作是复数。阅读很长,但因为它规定了如何解决操作,所以一个很好的资源是:http://guides.rubyonrails.org/routing.html

让我们跟随一些代码进入兔子洞,从 redirect_to @user

开始

redirect_to 执行重定向 location 设置为 url_for(@user) link

def redirect_to(options = {}, response_status = {}) #:doc:
  ...
  self.location      = _compute_redirect_to_location(request, options)
  ...
end

def _compute_redirect_to_location(request, options) #:nodoc:
  ...
  else
    url_for(options)
 ...
end

到目前为止,还不错。 redirect_to 对如何确定路径没有发言权。接下来我们来看url_forlink

def url_for(options = nil)
  ...
  else
    ...
    builder = ActionDispatch::Routing::PolymorphicRoutes::HelperMethodBuilder.send(method)
    ...
      builder.handle_model_call(self, options)
    ...
end

看起来 url_for 负责决定如何构建 url。在这种情况下,它被发送到 HelperMethodBuilder。 link

   def handle_model_call(target, model)
      method, args = handle_model model
      target.send(method, *args)
   end

   def handle_model(record)
      ...
      named_route = if model.persisted?
                      ...
                      get_method_for_string model.model_name.singular_route_key
                    ...
      [named_route, args]
   end

   def get_method_for_string(str)
     "#{prefix}#{str}_#{suffix}"
   end

好了。 handle_model 获取(持久化)记录的 model_name,其中 return 是一个 ActiveModel::Name 对象,并从中获取 singular_route_key

pry(main)> User.first.model_name.singular_route_key  
=> "user"

get_method_for_string使用singular_route_key完成辅助方法调用。我将推导 "prefix"/"suffix" 的逻辑作为学术练习,但它应该 return "user_path".

所以,为了回答这个问题,单数形式被编码到 ActiveModel::Name 和 HelperMethodBuilder 中。希望对您有所帮助!