Method: ActionDispatch::Journey::Formatter#generate

Defined in:
actionpack/lib/action_dispatch/journey/formatter.rb

#generate(name, options, path_parameters) ⇒ Object



61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'actionpack/lib/action_dispatch/journey/formatter.rb', line 61

def generate(name, options, path_parameters)
  original_options = options.dup
  path_params = options.delete(:path_params) || {}
  options = path_params.merge(options)
  constraints = path_parameters.merge(options)
  missing_keys = nil

  match_route(name, constraints) do |route|
    parameterized_parts = extract_parameterized_parts(route, options, path_parameters)

    # Skip this route unless a name has been provided or it is a standard Rails
    # route since we can't determine whether an options hash passed to url_for
    # matches a Rack application or a redirect.
    next unless name || route.dispatcher?

    missing_keys = missing_keys(route, parameterized_parts)
    next if missing_keys && !missing_keys.empty?
    params = options.delete_if do |key, _|
      # top-level params' normal behavior of generating query_params should be
      # preserved even if the same key is also a bind_param
      parameterized_parts.key?(key) || route.defaults.key?(key) ||
        (path_params.key?(key) && !original_options.key?(key))
    end

    defaults       = route.defaults
    required_parts = route.required_parts

    route.parts.reverse_each do |key|
      break if defaults[key].nil? && parameterized_parts[key].present?
      next if parameterized_parts[key].to_s != defaults[key].to_s
      break if required_parts.include?(key)

      parameterized_parts.delete(key)
    end

    return RouteWithParams.new(route, parameterized_parts, params)
  end

  unmatched_keys = (missing_keys || []) & constraints.keys
  missing_keys = (missing_keys || []) - unmatched_keys

  MissingRoute.new(constraints, missing_keys, unmatched_keys, routes, name)
end