I am implementing a simple language switcher in the common HTML menu-bar on a website in Rails, where the locale is path-based with the Rails-standard I18n implementation, e.g., /en/articles
for Index for the Article model in English (in the following example, I consistently use pages for the model Article
).
The language switcher is a simple text link (<a>
in HTML) to the same page in another language. For example, the French page for /en/article/7
should be /fr/article/7
.
Here is the most simplified code for the language-switcher link, which preserves all the GET query parameters for the current page:
str_link = link_to("fr", url_for(locale: "fr", params: request.query_parameters.except("locale")))
This code is included inside the common layout /app/views/layouts/application.html.erb
so that it is applied to all pages on the website.
This works most of time but fails on the page after a user-input to a new
page turns out to be invalid (status: :unprocessable_entity
), according to the Rails standard CRUD action.
In the new
page, the required link for the language switcher for French should be /fr/article/new
; the above code-snippet works fine when a user freshly opens the new
page in English (/en/article/new
). However, once a user's input turns out to be invalid, the given URL is /en/articles
, whose contents are equivalent to the new
page.
How can I obtain the path /en/article/new
in such cases so as to make the language switcher provide the correct link?
Obviously, when a user just requests the Index page /en/articles
, the counterpart French page is /fr/articles
, the URL of which is identical to the failed new
page. So, they must be distinguished, that is, the path cannot be guessed thoroughly from the current URL and it depends on whether it is a fresh request or unprocessable_entity
.
An answer to the question "Ruby on Rails Link to Previous Page on Form Failing After Invalid Input" suggests implementing hidden_field
that contains the new
page URL and the algorithm uses it. However, the suggestion does not work well in this case because the hidden_field
for action create
is POST and not a GET parameter. In the present case of the common language switcher, I need to deal with an arbitrary number of models inside the common layout (application.html.erb
), meaning which parameter in params
to permit cannot be pre-determined and hence to access hidden_field
in params
is tricky.
Here are the routes and Article
Controller generated according to the Rails standard:
% bin/rails g scaffold Article title:string content:text
Routes:
# config/routes.rb
Rails.application.routes.draw do
filter :locale
resources :articles
end
Article
Controller:
# app/controllers/articles_controller.rb
class ArticlesController < ApplicationController
def create
@article = Article.new(article_params)
respond_to do |format|
if @article.save
format.html { redirect_to article_url(@article), notice: "Article was successfully created." }
else
format.html { render :new, status: :unprocessable_entity }
end
end
end
private
def article_params
params.require(:article).permit(:title, :content)
end
end
I am using Rails 7.0. But I think the Rails version is almost irrelevant.