title: How to pass options like `only_path: true` and `anchor:` to `url_for` when generating a route from an array or object (instead of from a hash)
body: <p>I'm trying to change a function — which currently only accepts a URL (path) <em>string</em> — to make it more flexible, so that it will also accept as input the same arguments that you can pass to <code>url_for</code>. The problem is, <code>url_for</code> returns a full URL including protocol/host, and I only want the path portion...</p>
  
  <p><a href="https://api.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html#method-i-url_for" rel="noreferrer"><code>url_for</code></a> has a lovely <code>only_path: true</code> option that makes it skip adding the protocol/host. This works great as long as you're passing it as part of a single hash to <code>url_for</code>:</p>
  
  <pre><code>main &gt; app.url_for(controller: 'users', action: 'index', only_path: true)
  =&gt; "/users"
  </code></pre>
  
  <p>But how do you pass options when you are passing an <em>array</em> or a <em>model object</em> to <code>url_for</code>?</p>
  
  <pre><code>main &gt; 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 &gt; 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'
  </code></pre>
  
  <p>You can't! Clearly, it's not even syntactically possible to pass an options hash if you're passing anything other than a hash, since <a href="https://api.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html#method-i-url_for" rel="noreferrer">it</a>s arity is <code>0..1</code> and it only takes a single argument: <code>url_for(options = nil)</code>.</p>
  
  <hr>
  
  <p>So my question is, is there a Rails helper that takes the same options as <code>url_for</code> (including <code>anchor:</code>) but returns a path?</p>
  
  <p>I suppose it wouldn't be too hard to add one, like <a href="https://grosser.it/2009/08/26/path_for-rails-helper/" rel="noreferrer">this one</a>, that uses <code>URI.parse(path).path</code> (probably what I'll do for now)... but that seems inefficient, inelegant, and inconsistent.</p>
  
  <p><strong>Inefficient</strong> and <strong>inelegant</strong> because it generates a string containing extra unwanted information and then has to parse it, convert it to a structured data structure, and then convert it <em>back</em> to a string <em>without</em> the unwanted information.</p>
  
  <p><strong>Inconsistent</strong> because:</p>
  
  <ol>
  <li><p>Rails includes a <code>_path</code> variant for every <code>_url</code> route helper. Why doesn't it have a built-in "path" variant of <code>url_for</code> (or does it and it's called something else?)?</p></li>
  <li><p><em>Other</em> routing helpers that accept an object or array—such as <code>polymorphic_path</code>— let you pass in options too:</p></li>
  </ol>
  
  <p>Example:</p>
  
  <pre><code>main &gt; app.polymorphic_url [user, :notification_preferences], anchor: 'foo'
  =&gt; "http://example.com/users/4/notification_preferences#foo"
  
  main &gt; app.polymorphic_path [user, :notification_preferences], anchor: 'foo'
  =&gt; "/users/4/notification_preferences#foo"
  
  main &gt; app.polymorphic_path user, anchor: 'foo'
  =&gt; "/users/4#foo"
  </code></pre>
  
  <p><code>ActionDispatch::Routing::RouteSet</code> actually has a <code>path_for</code>:</p>
  
  <pre><code>  # strategy for building urls to send to the client                        
    PATH    = -&gt;(options) { ActionDispatch::Http::URL.path_for(options) }     
    UNKNOWN = -&gt;(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    
      ...
  </code></pre>
  
  <p>— just not <code>ActionDispatch::Routing::UrlFor</code>, apparently. Anyway, <code>ActionDispatch::Routing::RouteSet#path_for</code> is buried too deep in internals to be helpful to me; I need a helper that is callable from the controller/view.</p>
  
  <p>So, what is a good solution for this that is elegant, consistent with other Rails routing helpers, and relatively efficient (no <code>URI.parse</code>)?</p>
  
  <hr>
  
  <p>Better yet, is there any reason the method signature of the built-in <code>url_for</code> couldn't simply be modified (in a future version of Rails, by submitting a pull request) to allow both a subject (model object, array, or hash) <em>and</em> any number of optional <code>options</code> to be passed in?</p>
  
  <p>Probably the original <code>url_for</code> was written before Ruby had keyword arguments. But nowadays, it's pretty trivial to do exactly that: accept an "object" plus any number of optional keyword options:</p>
  
  <pre><code>def url_for(object = nil, **options)
    puts "object: #{object.inspect}"
    puts "options: #{options.inspect}"
  end
  
  main &gt; url_for ['user', :notification_preferences], anchor: 'anchor'
  object: ["user", :notification_preferences]
  options: {:anchor=&gt;"anchor"}
  =&gt; nil
  
  main &gt; url_for ['user', :notification_preferences], only_path: true
  object: ["user", :notification_preferences]
  options: {:only_path=&gt;true}
  </code></pre>
  
  <p>Is there any reason we couldn't/shouldn't change <code>url_for</code>'s method signature to <code>url_for(object = nil, **options)</code>?</p>
  
  <p>How would you modify <code>url_for</code>/<code>full_url_for</code> such that it remained as backwards compatible as possible but also let you call it with an array + keyword options?</p>