Home > Blockchain >  what is the context for _url and _path in rails
what is the context for _url and _path in rails

Time:12-31

Rails.application.routes.draw do
  resources :carts
  ...
end

Now in controller, I can

cart_url(@cart)

or in view, I can

<%= link_to 'New Cart', new_cart_path %>

In which context are cart_url and new_cart_path defined? (how to see those in rails console)

In rails console, I tried:

irb(main):053:0> ApplicationController.new.rails_postmark_inbound_emails_path
Traceback (most recent call last):
        2: from (irb):53
        1: from (irb):53:in `rescue in irb_binding'
NoMethodError (undefined method `host' for nil:NilClass)
irb(main):058:0> CartsController.new.carts_url
Traceback (most recent call last):
        2: from (irb):58
        1: from (irb):58:in `rescue in irb_binding'
NoMethodError (undefined method `host' for nil:NilClass)
irb(main):056:0> CartsController.new_line_item_url
Traceback (most recent call last):
        2: from (irb):56
        1: from (irb):56:in `rescue in irb_binding'
NoMethodError (undefined method `new_line_item_url' for CartsController:Class)

CodePudding user response:

The context for the route helpers is actually an anomynous module.

# This code was abbreviated for StackOverflow
module ActionDispatch
  # A NamedRouteCollection instance is a collection of named routes, and also
  # maintains an anonymous module that can be used to install helpers for the
  # named routes.
  class NamedRouteCollection
    include Enumerable
    attr_reader :routes, :url_helpers_module, :path_helpers_module
    private :routes

    def initialize
      @routes = {}
      @path_helpers = Set.new
      @url_helpers = Set.new
      @url_helpers_module  = Module.new
      @path_helpers_module = Module.new
    end

    def add(name, route)
      key       = name.to_sym
      path_name = :"#{name}_path"
      url_name  = :"#{name}_url"

      if routes.key? key
        @path_helpers_module.undef_method path_name
        @url_helpers_module.undef_method url_name
      end
      routes[key] = route

      helper = UrlHelper.create(route, route.defaults, name)
      define_url_helper @path_helpers_module, path_name, helper, PATH
      define_url_helper @url_helpers_module, url_name, helper, UNKNOWN

      @path_helpers << path_name
      @url_helpers << url_name
    end

    def get(name)
      routes[name.to_sym]
    end

    def key?(name)
      return unless name
      routes.key? name.to_sym
    end

    alias []=   add
    alias []    get
    alias clear clear!

    def each(&block)
      routes.each(&block)
      self
    end

    def names
      routes.keys
    end

    def length
      routes.length
    end

    # Given a  name , defines name_path and name_url helpers.
    # Used by 'direct', 'resolve', and 'polymorphic' route helpers.
    def add_url_helper(name, defaults, &block)
      helper = CustomUrlHelper.new(name, defaults, &block)
      path_name = :"#{name}_path"
      url_name = :"#{name}_url"

      @path_helpers_module.module_eval do
        redefine_method(path_name) do |*args|
          helper.call(self, args, true)
        end
      end

      @url_helpers_module.module_eval do
        redefine_method(url_name) do |*args|
          helper.call(self, args, false)
        end
      end

      @path_helpers << path_name
      @url_helpers << url_name

      self
    end
  end
  # ...
end

This module is created before the request is passed to a controller when ActionDispatch reads the route file and builds a routes collection.

And the controller then includes both the url_helpers and path_helpers modules. How this method ends up in the view is a topic upon itself but the gist is that ActionView::Context provides the methods and instance variables of the controller as the context (self) to the templating engine (ERB, Slim, Haml, jBuilder etc).

You can call the route helpers in the console via app. Thats because the console session is actually an integration test (

  • Related