I'm trying to get Globalize3 working on my app. I have the toy projet of blog posts, that I want to translate.
My urls look like this : localhost/en/posts
localhost/fr/posts
Here's how I do it in my ApplicationController
before_action :set_locale
def set_locale
I18n.locale = params[:locale] if params[:locale] || I18n.default_locale
end
I'm using the same form_for
for creating and updating posts. Here's the view code :
<%= form_for(@post) do |f| %>
...
<% end %>
It works fine for when I go to the /new
page, here's the controller code:
def new
@post = Post.new
end
def create
@post = Post.new(post_params)
if @post.save
redirect_to action: :show, id: @post.id
else
render 'new'
end
end
But when I try to edit a post with the url /en/posts/1/edit
, it mixes the parameters passed to the form_for
. That's the error message:
No route matches {:action=>"show", :controller=>"posts", :locale=>#, :id=>nil, :format=>nil} missing required keys: [:locale, :id]
My question is : why does it do that and how can I fix thix?
I've already tried some things like changing the form_for
declaration to this:
<%= form_for(@post, url: {action: 'show', id: @post, locale: params[:locale]} ) do |f| %>
so it works with update
but not with new
because my post doesn't have an id
No route matches {:action=>"show", :locale=>"en", :id=>#<Post id: nil, created_at: nil, updated_at: nil, title: nil, text: nil>, :controller=>"posts"}
So yeah, I don't really want to use 2 forms for create and update if I can avoid doing it. Is there a good way of doing this?
edit:
here's my rake routes
Prefix Verb URI Pattern Controller#Action
posts GET /:locale/posts(.:format) posts#index {:locale=>/en|fr/}
POST /:locale/posts(.:format) posts#create {:locale=>/en|fr/}
new_post GET /:locale/posts/new(.:format) posts#new {:locale=>/en|fr/}
edit_post GET /:locale/posts/:id/edit(.:format) posts#edit {:locale=>/en|fr/}
post GET /:locale/posts/:id(.:format) posts#show {:locale=>/en|fr/}
PATCH /:locale/posts/:id(.:format) posts#update {:locale=>/en|fr/}
PUT /:locale/posts/:id(.:format) posts#update {:locale=>/en|fr/}
DELETE /:locale/posts/:id(.:format) posts#destroy {:locale=>/en|fr/}
It's maybe a little extra work but still an accepted pattern to have a separate form container for the new and edit actions, such as this:
new.html.erb
<%= form_for(@post, url: posts_path) do |f| %>
<%= render 'form', f: f %>
<%= f.submit 'Create' %>
<% end %>
edit.html.erb
<%= form_for(@post, url: post_path(@post)) do |f| %>
<%= render 'form', f: f %>
<%= f.submit 'Update' %>
<% end %>
So that's one option. You render the common form fields in the _form.html.erb
partial and do whatever's unique to your new/edit in their respective form containers.
But, if you'd really like to have just one form container file you can always do this:
<%= form_for(@post, url: (@post.new_record? ? posts_path : post_path(@post)) ) do |f| %>
Note: I'm not exactly sure how the locales gem works so I excluded that above... but if you do need to include the locale explicitly you can do that with e.g. post_path(@post, locale: params[:locale])
. Recall that post_path(@post)
is actually short-hand for post_path(id: @post)
. That is, the parameters you pass into the named route are ordered the same as your route expects them if not explicitly stated.