iT邦幫忙

2022 iThome 鐵人賽

DAY 26
1
Modern Web

從0開始刻 淺談 Rails 的運作魔法系列 第 26

Day 26 - Real Routing - 試試 match 方法

  • 分享至 

  • xImage
  •  

首先,我們將引進 match
match 會將參數記憶起來,然後去 match URL

# rainbow/lib/rainbow/routing.rb
  module Rainbow
    class RouteObject
      def match(url, *args)
        options = {}
        options = args.pop if args[-1].is_a?(Hash)
        options[:default] ||= {}
        dest = nil
        dest = args.pop if args.size > 0
        raise "Too many args!" if args.size > 0
        parts = url.split("/")
        parts.select! { |p| !p.empty? }
        vars = []
        regexp_parts = parts.map do |part|
          if part[0] == ":"
            vars << part[1..-1]
            "([a-zA-Z0-9]+)"
          elsif part[0] == "*"
            vars << part[1..-1]
            "(.*)"
          else 
            part
          end
        end
        regexp = regexp_parts.join("/")
          @rainbow.push({
            :regexp => Regexp.new("^/#{regexp}$"),
            :vars => vars,
            :dest => dest,
            :options => options,
          }) 
        end
      end 
    end

第一行會去抓 option 這個 hash 並執行 args.pop

然後,我們會去抓 URL

並且用 / 去拆開

使用正則表達式去比對運達式,並抓出對應的值

並把他們放到一個陣列中

最終,我們將所有 index 值集結,放到一個 hash 中當作 params

# rainbow/lib/rainbow/routing.rb
  module Rainbow
    class RouteObject
      def check_url(url)
        @rainbow.each do |r|
        m = r[:regexp].match(url)
        if m
          options = r[:options]
          params = options[:default].dup
          r[:vars].each_with_index do |v, i|
            params[v] = m.captures[i]
          end
          if r[:dest]
            return get_dest(r[:dest], params)
          else
            controller = params["controller"]
            action = params["action"]
            return get_dest("#{controller}" + "##{action}", params)
          end
        end 
      end
      nil 
    end
  
    def get_dest(dest, routing_params = {})
      return dest 
      if dest.respond_to?(:call)
        if dest =~ /^([^#]+)#([^#]+)$/
          name = $1.capitalize
          con = Object.const_get("#{name}Controller")
          return con.action($2, routing_params)
        end
        raise "No destination: #{dest.inspect}!"
      end 
    end
  end

check_url 會透過依照這個規範找到第一個符合條件的值

假如 match 到,他會做一個 params 物件,並且去比對正則表達式,抓出符合條件的變數

假如這個條件有 controller#action,會呼叫 get_dest 並加入到 Rack 應用程式中

沒有的話就會去抓 :controller and :action 這兩個變數

同樣呼叫 get_dest 加入到 Rack 應用程式中

不過究竟是怎麼加入到 Rack 應用程式?

首先,確認 call() 方法是否有回應,有的話就返回符合條件的值

如果已經存在在 Rack 應用程式中,我們可以直接使用它

除此之外,我們會將值放上 #

讓他去尋找 controller 中的 action

當我們抓到,我們可以傳遞 routing 中的參數

這就是為什麼我們會在 controller 的 action() 中放參數的原因


上一篇
Day 25 - 設定 Router
下一篇
Day 27 - Real Routing - Route 運作
系列文
從0開始刻 淺談 Rails 的運作魔法30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言