我试图修改一个函数--它目前只接受URL(path)* string *--使它更灵活,这样它也可以接受您传递给url_for
的相同参数作为输入。问题是,url_for
返回一个完整的URL,包括protocol/host,而我只需要路径部分...url_for
有一个可爱的only_path: true
选项,可以跳过添加协议/主机,只要你把它作为一个散列的一部分传递给url_for
,这个选项就能很好地工作:
main > app.url_for(controller: 'users', action: 'index', only_path: true)
=> "/users"
但是,当您向url_for
传递 * array * 或 * model object * 时,如何传递选项呢?
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'
显然,如果你传递的不是哈希值,那么从语法上来说,传递选项哈希值是不可能的,因为它的arity是0..1
,而且它只接受一个参数:url_for(options = nil)
.
所以我的问题是,是否有一个Rails帮助器,它采用与url_for
相同的选项(包括anchor:
),但返回一个路径?
我想添加一个使用URI.parse(path).path
(可能是我现在要做的)的this one并不太难......但这似乎效率低下、不优雅且不一致。
- 低效和不优雅**,因为它生成包含额外不需要的信息的字符串,然后必须解析它,将它转换为结构化数据结构,然后将它转换 * 回 * 没有 * 不需要的信息的字符串。
- 不一致**原因:
- Rails为每个
_url
route helper都提供了一个_path
变量,为什么它没有内置的url_for
"path"变量(或者它有,但它被称为其他变量?)
1.* Other * 接受对象或数组的路由助手(如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
在内部埋得太深,对我没有帮助;我需要一个可以从控制器/视图调用的助手。
那么,什么是一个好的解决方案,它是优雅的,与其他Rails路由助手一致,并且相对高效(没有URI.parse
)?
更好的是,内置url_for
的方法签名不能简单地修改(在Rails的未来版本中,通过提交一个pull请求)以允许传入一个subject(模型对象、数组或散列)* 和 * 任意数量的可选options
,这有什么原因吗?
最初的url_for
可能是在Ruby有关键字参数之前编写的,但是现在,要做到这一点已经很容易了:接受"object"加上任意数量的可选关键字选项:
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
,使其尽可能保持向后兼容,同时允许使用数组+关键字选项调用它?
1条答案
按热度按时间zaqlnxep1#
这里有一个潜在的解决方案,显示了我正在寻找的东西:
(与原始Rails版本的源代码比较)
我还没有试着对这段代码运行Rails测试套件,所以它很可能遗漏了一些东西,但到目前为止,它似乎对我的简单测试有效:
让我知道,如果你发现任何错误,在这方面或有任何改进,或可以想到一个更清洁的方式来完成这一点。
请张贴任何改进的版本,你可能有作为答案!