Rails 4:如何以DRY方式为routes.rb中包含点的字符串参数定义约束?
Rails 4: How to define a constraint for string param containing dots in routes.rb the DRY way?
如何绘制以 IPv4 地址为参数的路由。就像这样:
http://localhost:3000/ip/192.168.2.2
仅当 request.params[:ipaddress]
是 IPv4 地址时才应使用此路由,但我得到的只是:No route matches [GET] "/ip/192.168.2.2"
第一次尝试:constraints: { ipaddress: /^regexp$/ }
在 .config/routes.rb
中定义内联约束表达式,如下所示:
resources :ipaddresses, path: :ip, param: :ipaddress, constraints: {
ipaddress: /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ }, only: :show
导致错误,服务器无法启动:
/home/mschmidt/.rvm/gems/ruby-2.2.3/gems/actionpack-4.2.4/lib/action_dispatch/routing/mapper.rb:207:in
`verify_regexp_requirement': Regexp anchor characters are not allowed in routing requirements
第二次尝试:没有锚字符
如果我删除锚字符,服务器确实会启动,但约束没有表达想要的内容。该字符串现在可以包含 一个或多个 个 IPv4 地址。
第三次尝试:将其移至函数
因此,我使用名为 matches?
的方法将表达式放入 class 中。如果参数没有任何点,这就完美了。不幸的是,所有这些 IP 都有一些点,我又回到了起点:
No route matches [GET] "/ip/192.168.2.2"
/config/routes.rb:
Rails.application.routes.draw do
class IPv4Constraint
def matches?(request)
request.params[:ipaddress] =~ /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
end
end
resources :ipaddresses, path: :ip, param: :ipaddress, constraints: IPv4Constraint.new, only: :show
end
因为这些点,我必须在 routes.rb 中定义一个约束,而且我认为将更多代码放入控制器中不会很枯燥。做这个的最好方式是什么?有没有办法用一个表达式来做到这一点?
我现在要使用 routing-filter。
将 gem 添加到 Gemfile 后:
gem 'routing-filter'
我添加了一个新过滤器:
# The IPv4Address filter extracts segments matching /ip/:IPv4Address from the
# end of the recognized url and exposes the page parameter as
# params[:ipv4address]. When a url is generated the filter adds the address to
# the url accordingly if the page parameter is passed to the url helper.
#
# incoming url: /ip/192.168.2.2
# filtered url: /ip
# generated url: /ip/192.168.2.2
#
# You can install the filter like this:
#
# # in config/routes.rb
# Rails.application.routes.draw do
# filter :ipv4address
# end
module RoutingFilter
class Ipv4address < Filter
IPV4ADDRESS_PATTERN = %r(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)
def around_recognize(path, env, &block)
pattern = pattern_builder(path)
ipv4address = extract_segment!(pattern, path)
yield.tap do |params|
params[:ipv4address] = ipv4address if ipv4address
end
end
def around_generate(params, &block)
ipv4address = params.delete(:ipv4address)
yield.tap do |result|
append_segment!(result, "ip/#{ipv4address}") if append_ipv4address?(ipv4address)
end
end
private
def pattern_builder(path)
ipv4address = extract_ipv4address(path)
build = "/(#{ipv4address.gsub('.','\.')})/?$"
/#{build}/
end
def extract_ipv4address(path)
path.match(IPV4ADDRESS_PATTERN).to_s
end
def append_ipv4address?(ipv4address)
ipv4address && !ipv4address.blank?
end
end
end
在 routes.rb 中调用它并将操作从 show
更改为 index
filter :ipv4address
resources :ipaddresses, path: :ip, only: :index
IP 现在在我的控制器中可用 params[:ipv4address]
如何绘制以 IPv4 地址为参数的路由。就像这样:
http://localhost:3000/ip/192.168.2.2
仅当 request.params[:ipaddress]
是 IPv4 地址时才应使用此路由,但我得到的只是:No route matches [GET] "/ip/192.168.2.2"
第一次尝试:constraints: { ipaddress: /^regexp$/ }
在 .config/routes.rb
中定义内联约束表达式,如下所示:
resources :ipaddresses, path: :ip, param: :ipaddress, constraints: {
ipaddress: /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/ }, only: :show
导致错误,服务器无法启动:
/home/mschmidt/.rvm/gems/ruby-2.2.3/gems/actionpack-4.2.4/lib/action_dispatch/routing/mapper.rb:207:in
`verify_regexp_requirement': Regexp anchor characters are not allowed in routing requirements
第二次尝试:没有锚字符
如果我删除锚字符,服务器确实会启动,但约束没有表达想要的内容。该字符串现在可以包含 一个或多个 个 IPv4 地址。
第三次尝试:将其移至函数
因此,我使用名为 matches?
的方法将表达式放入 class 中。如果参数没有任何点,这就完美了。不幸的是,所有这些 IP 都有一些点,我又回到了起点:
No route matches [GET] "/ip/192.168.2.2"
/config/routes.rb:
Rails.application.routes.draw do
class IPv4Constraint
def matches?(request)
request.params[:ipaddress] =~ /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/
end
end
resources :ipaddresses, path: :ip, param: :ipaddress, constraints: IPv4Constraint.new, only: :show
end
因为这些点,我必须在 routes.rb 中定义一个约束,而且我认为将更多代码放入控制器中不会很枯燥。做这个的最好方式是什么?有没有办法用一个表达式来做到这一点?
我现在要使用 routing-filter。
将 gem 添加到 Gemfile 后:
gem 'routing-filter'
我添加了一个新过滤器:
# The IPv4Address filter extracts segments matching /ip/:IPv4Address from the
# end of the recognized url and exposes the page parameter as
# params[:ipv4address]. When a url is generated the filter adds the address to
# the url accordingly if the page parameter is passed to the url helper.
#
# incoming url: /ip/192.168.2.2
# filtered url: /ip
# generated url: /ip/192.168.2.2
#
# You can install the filter like this:
#
# # in config/routes.rb
# Rails.application.routes.draw do
# filter :ipv4address
# end
module RoutingFilter
class Ipv4address < Filter
IPV4ADDRESS_PATTERN = %r(((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)
def around_recognize(path, env, &block)
pattern = pattern_builder(path)
ipv4address = extract_segment!(pattern, path)
yield.tap do |params|
params[:ipv4address] = ipv4address if ipv4address
end
end
def around_generate(params, &block)
ipv4address = params.delete(:ipv4address)
yield.tap do |result|
append_segment!(result, "ip/#{ipv4address}") if append_ipv4address?(ipv4address)
end
end
private
def pattern_builder(path)
ipv4address = extract_ipv4address(path)
build = "/(#{ipv4address.gsub('.','\.')})/?$"
/#{build}/
end
def extract_ipv4address(path)
path.match(IPV4ADDRESS_PATTERN).to_s
end
def append_ipv4address?(ipv4address)
ipv4address && !ipv4address.blank?
end
end
end
在 routes.rb 中调用它并将操作从 show
更改为 index
filter :ipv4address
resources :ipaddresses, path: :ip, only: :index
IP 现在在我的控制器中可用 params[:ipv4address]