Frage

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/}
War es hilfreich?

Lösung

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top