-->

`link_to` with parameters for an Engine route

2019-06-21 04:15发布

问题:

(While this discusses Blacklight engine, I believe the question is actually purely about Rails.)

Continuing my quest from scope around mount ineffective? (tl;dr: make the engine routes obey the same :locale scope as application routes), after digging through Rails source.

Currently, I have this setup:

# config/routes.rb
Rails.application.routes.draw do      
  Blacklight::Engine.routes.default_scope = { path: "(:locale)", locale: /en|ja/ }
  mount Blacklight::Engine => '/'

  scope "(:locale)", locale: /en|ja/ do
    # ...
  end
end

This makes the routes work properly. However, I had this view code to generate the alternate-language links to the current page (guided by link_to the current page plus/merged with a param [duplicate]):

<div id="languages_nav_popup" class="navbar-inverse">                                                                                                                                                          
  <% locales.each do |locale| %>
    <% next if locale == I18n.locale %>
    <%= link_to params.permit!.merge(locale: locale) do %>                                             
      <img src="<%= url_for "/img/flag/#{locale}.png" %>"/>                                            
    <% end %>
  <% end %>
</div>

That link_to fails when the current page is an Engine route. This is due to this piece of code in actionpack:

# lib/action_dispatch/journey/formatter.rb
# 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?

With link_to options, &block syntax that I use above, name is nil; and dispatcher? is false for an engine route. (If I pass that check by inserting a name by force, I get a nonsensical URL like .../assets?action=index&controller=saved_searches&locale=ja).

I'm getting desperate here, almost to the point where I'm thinking the best way to deal with this is regexp. This atrocity works:

<%= link_to request.base_url + request.original_fullpath.sub(%r{(?<=/)#{I18n.locale}}, locale.to_s) do %

Is there no way to generate the correct URL properly?

回答1:

Another totally hacky solution is to copy the engine routes to your local routes.rb and add a warning that triggers on gem update to check them for changes. :(