gpt4 book ai didi

ruby - 从数组或对象(而不是散列)生成路由时,如何将 `only_path: true` 和 `anchor:` 等选项传递给 `url_for`

转载 作者:太空宇宙 更新时间:2023-11-03 16:40:42 25 4
gpt4 key购买 nike

我正在尝试更改一个函数——它目前只接受一个 URL(路径)字符串——以使其更加灵活,这样它也将接受与你可以接受的相同参数作为输入传递给 url_for。问题是,url_for 返回一个完整的 URL,包括协议(protocol)/主机,而我只想要路径部分...

url_for有一个可爱的 only_path: true 选项,可以跳过添加协议(protocol)/主机。只要您将它作为单个散列的一部分传递给 url_for,这就很好用:

main > app.url_for(controller: 'users', action: 'index', only_path: true)
=> "/users"

但是,当您将数组模型对象 传递给url_for 时,您如何传递选项呢?

main > app.url_for(user, only_path: true)
ArgumentError: wrong number of arguments (given 2, expected 0..1)
from /gems/actionpack-5.1.6/lib/action_dispatch/routing/url_for.rb:166:in `url_for'

main > app.url_for([user, :notification_preferences], only_path: true)
ArgumentError: wrong number of arguments (given 2, expected 0..1)
/actionpack-5.1.6/lib/action_dispatch/routing/url_for.rb:166:in `url_for'

你不能!显然,如果你传递的不是散列,那么从句法上来说,传递选项散列是不可能的,因为 it s arity 是 0..1,它只需要一个参数:url_for(options = nil)


所以我的问题是,是否有一个 Rails 助手采用与 url_for 相同的选项(包括 anchor:)但返回路径?

我想添加一个不会太难,比如 this one ,它使用 URI.parse(path).path(可能是我现在要做的)...但这似乎效率低下、不够优雅且不一致。

低效不雅,因为它会生成一个包含额外不需要信息的字符串,然后必须对其进行解析,将其转换为结构化数据结构,然后再将其转换返回到一个字符串没有不需要的信息。

不一致因为:

  1. Rails 为每个 _url 路由助手包含一个 _path 变体。为什么它没有 url_for 的内置“路径”变体(或者它有并且它被称为其他东西?)?

  2. 其他接受对象或数组的路由助手——例如polymorphic_path——也让你传递选项:

例子:

main > app.polymorphic_url [user, :notification_preferences], anchor: 'foo'
=> "http://example.com/users/4/notification_preferences#foo"

main > app.polymorphic_path [user, :notification_preferences], anchor: 'foo'
=> "/users/4/notification_preferences#foo"

main > app.polymorphic_path user, anchor: 'foo'
=> "/users/4#foo"

ActionDispatch::Routing::RouteSet 实际上有一个 path_for:

  # strategy for building urls to send to the client                        
PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }

def path_for(options, route_name = nil)
url_for(options, route_name, PATH)
end

# The +options+ argument must be a hash whose keys are *symbols*.
def url_for(options, route_name = nil, url_strategy = UNKNOWN)
options = default_url_options.merge options
...

— 显然不是 ActionDispatch::Routing::UrlFor。无论如何,ActionDispatch::Routing::RouteSet#path_for 内部结构太深,对我没有帮助;我需要一个可从 Controller / View 调用的助手。

那么,什么是优雅、与其他 Rails 路由助手一致且相对高效(无 URI.parse)的好解决方案?


更好的是,有什么理由不能简单地修改内置 url_for 的方法签名(在 Rails 的 future 版本中,通过提交拉取请求)以允许主题(模型对象、数组或散列)要传入的任意数量的可选选项

可能原始的 url_for 是在 Ruby 有关键字参数之前写的。但如今,做到这一点非常简单:接受一个“对象”加上任意数量的可选关键字选项:

def url_for(object = nil, **options)
puts "object: #{object.inspect}"
puts "options: #{options.inspect}"
end

main > url_for ['user', :notification_preferences], anchor: 'anchor'
object: ["user", :notification_preferences]
options: {:anchor=>"anchor"}
=> nil

main > url_for ['user', :notification_preferences], only_path: true
object: ["user", :notification_preferences]
options: {:only_path=>true}

有什么理由我们不能/不应该将 url_for 的方法签名更改为 url_for(object = nil, **options)

您将如何修改 url_for/full_url_for,使其尽可能保持向后兼容,同时让您使用数组 + 关键字选项调用它?

最佳答案

这是一个可能的解决方案,它显示了我正在寻找的东西:

  def url_for(object = nil, **options)
full_url_for(object, **options)
end

def full_url_for(object = nil, **options)
path_or_url_for = ->(*args) {
if options[:only_path]
_routes.path_for(*args)
else
_routes.url_for( *args)
end
}
polymorphic_path_or_url = ->(*args) {
if options[:only_path]
polymorphic_path(*args)
else
polymorphic_url( *args)
end
}

case object
when nil, Hash, ActionController::Parameters
route_name = options.delete :use_route
merged_url_options = options.to_h.symbolize_keys.reverse_merge!(url_options)
path_or_url_for.(merged_url_options, route_name)
when String
object
when Symbol
HelperMethodBuilder.url.handle_string_call self, object
when Array
components = object.dup
polymorphic_path_or_url.(components, components.extract_options!)
when Class
HelperMethodBuilder.url.handle_class_call self, object
else
HelperMethodBuilder.url.handle_model_call self, object
end
end

(比较 original Rails version 的来源)

我还没有尝试针对这段代码运行 Rails 测试套件,所以它很可能遗漏了一些东西,但到目前为止它似乎适用于我的简单测试:

main > app.url_for(controller: 'users', action: 'index')
=> "http://example.com/users"

main > app.url_for(controller: 'users', action: 'index', only_path: true)
=> "/users"

main > app.url_for [user, :notification_preferences]
=> "http://example.com/users/4/notification_preferences"

main > app.url_for [user, :notification_preferences], only_path: true
=> "/users/4/notification_preferences"

如果您发现其中的任何错误或有任何改进,或者可以想出一种更简洁的方法来完成此操作,请告诉我。

请发布您可能有的任何改进版本作为答案!

关于ruby - 从数组或对象(而不是散列)生成路由时,如何将 `only_path: true` 和 `anchor:` 等选项传递给 `url_for`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54085688/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com