0

I want to internationalize an external code (see github) with i18n for rails. I have read the guide for Rails Internationalization (I18n) API. Translating the text is not a problem, but the underlying code seems not to work properly anymore in all situations. Unfortunately, I'm not a rails/ruby expert.

From the log:

FATAL -- : ActionView::Template::Error (No route matches {:action=>"edit", :controller=>"plans", :format=>nil, :id=>nil, :locale=>115} missing required keys: [:id]):

So the problem is, that the parameter for the id (=115) is passed as locale instead as id.

To get i18n working I added the following code into app/controllers/application_controller.rb:

...
  before_action :set_locale

  protected

  def set_locale
    I18n.locale = params[:locale] || I18n.default_locale
  end

  def default_url_options(options = {})
    { locale: I18n.locale }.merge options
  end
...

Moreover, I wrapped the original routes in config/routes.rb:

Dmptool2::Application.routes.draw do
  scope "(:locale)", locale: /en|de/ do
    a lot of original routes
  end
end

Therefore, the question is, is there a missing route or is there a problem inside the code or is it just my fault. Besides translating text and buttons, I haven't changed the original code. The original routes.rb can be found on github (sry, I can't post the link because I don't have enough reputation). Any suggestions / help would be perfect.

Edit I think I'm a little bit closer. Maybe now it's more clear, why it isn't working. First of all the "full" stacktrace:

F, [2015-05-04T16:43:58.600384 #19289] FATAL -- : 
ActionView::Template::Error (No route matches {:action=>"edit", :controller=>"plans", :format=>nil, :id=>nil, :locale=>#<Plan id: 158, name: "asdfe", requirements_template_id: 59, solicitation_identifier: "",
 submission_deadline: nil, visibility: :public, created_at: "2015-05-04 14:41:33", updated_at: "2015-05-04 14:43:48", current_plan_state_id: 300>} missing required keys: [:id]):
    2: 
    3: The plan "<%= @vars[:plan].name %>" has been completed.
    4: 
    5: If you have questions pertaining to this action, please visit the DMP Overview page at <%= edit_plan_url(@vars[:plan]) %>
    6: 
    7: <%= render :partial => 'users_mailer/notification_boilerplate.text.erb' %>
  app/views/users_mailer/dmp_owners_and_co_committed.text.erb:5:in `_app_views_users_mailer_dmp_owners_and_co_committed_text_erb__754483862330985648_69917281861000'
  app/mailers/users_mailer.rb:32:in `notification'
  app/models/concerns/plan_email.rb:50:in `block in email_dmp_saved'
  app/models/concerns/plan_email.rb:49:in `email_dmp_saved'
  app/models/plan_state.rb:31:in `update_current_plan_state'
  app/controllers/plan_states_controller.rb:97:in `create_plan_state'
  app/controllers/plan_states_controller.rb:73:in `committed'

If I hit the "done" Button on the webpage, the function committed is called, wich calls create_plan_state(:committed). Within the definition of create_plan_state, there is the statement plan_state = PlanState.create( plan_id: @plan.id, state: state, user_id: current_user.id). This triggers a callback for after_create: update_current_plan_state:

def update_current_plan_state
  #update the current plan pointer in the plan model
  p = self.plan
  p.current_plan_state_id = self.id
  p.save!
end

Now, this triggers after_save: email_dmp_saved:

def email_dmp_saved
...
if current_state.state == :committed
  users = self.users
  users.delete_if {|u| !u[:prefs][:dmp_owners_and_co][:committed]}
  users.each do |user|
    UsersMailer.notification(
        user.email,
        "PLAN COMPLETED: #{self.name}",
        "dmp_owners_and_co_committed",
        {:user => user, :plan => self } ).deliver
  end

I think the definition of the notification is not important. But the 3rd last line calls "dmp_owners_and_co_committed", which is defined as:

Hello <%= @vars[:user].full_name %>,

The plan "<%= @vars[:plan].name %>" has been completed.

If you have questions pertaining to this action, please visit the DMP Overview page at <%= edit_plan_url(@vars[:plan]) %>

<%= render :partial => 'users_mailer/notification_boilerplate.text.erb' %>

And in _notification_boilerplate.text.erb there is:

You may change your notification preferences at <%= edit_user_url(@vars[:user].id) %>#tab_tab2 .

I think the problem is edit_plan_url and edit_user_url. Because if I add some random text as parameter it works...:

edit_plan_url("de",@vars[:plan])
and in _notification:
edit_user_url("de",@vars[:user].id)

The question is, why is it working? Is there a way to print the created route? Because in the stacktrace the route doesn't match because format and id is nil. Now I want to see the new route in order to know where my random string "de" is placed.

1 Answers1

0

Looks like your routes are expecting two params, and ordering it as it comes. There's a way to avoid it by using a named hash into the params passed:

edit_plan_url(id: @vars[:plan].id)

The Rails Automagic will use the symbol to identify the param and avoid the problem.

Jorge de los Santos
  • 4,583
  • 1
  • 17
  • 35
  • Regarding putting I18n.locale inside the call: This is an option, but the question is, why is this necessary. Because I thought that the task is done in default_url_options (within the application_controller). And this is working for many cases. My problem of doing this is, that I don't know the complete code. And if I fix this for this two cases, there may be ten more, which I don't know. Thus I thought, that I18n does it in a general way via default_url_options. – derDaywalker May 05 '15 at 13:56
  • Why are you using: edit_plan_url instead of edit_plan_path? Did you rename your routes? – Jorge de los Santos May 05 '15 at 14:24
  • This is not my code. I didn't changed anything regarding this piece of code, so I don't know why edit_plan_url is used instead of edit_plan_path. I think edit_plan_url is used, because the link is send via mail. My goal is to use that code, but to "implement" internationalization. We want to use this open source tool, but with a different language. If I'm done with internationalization, I will provide the authors the "new feature". – derDaywalker May 05 '15 at 14:39
  • But are you able to change the _url with _path? does it work? – Jorge de los Santos May 05 '15 at 14:41
  • Unfortunatelly it does not work (I just call `rake assets:precompile`, I hope this is enough). If I just use `edit_plan_path(@vars[:plan])`, then I get the same no route matches error. If I add `edit_plan_path("xy",@vars[:plan])` I don't get the error. – derDaywalker May 05 '15 at 14:52
  • Use a named hash when passing the parameter: edit_plan_url(id: @vars[:plan].id). – Jorge de los Santos May 05 '15 at 15:07
  • Nice, if I use the "named hash" for `edit_user_url` and `edit_user_url(id: @vars[:user].id)` it works!! Why is that? Is this a programming issue of the original code? Do I have to search the complete code for url's without a named hash? By the way: Because of your question I noticed, that I have changed the code for edit_user_url. Originally it was `edit_user_url(@vars[:user])`, but last week I changed it to `edit_user_url(@vars[:user].id)` and forgot the undo it... – derDaywalker May 05 '15 at 15:47
  • I told you to name the params in my answer! Is it working then? Regards. – Jorge de los Santos May 05 '15 at 16:46
  • yes, as I already wrote. It's working if I use `edit_user_url(id: @vars[:user].id)`. But the question is, why is this necessary and do I have to do this for all URL's, not only for edit_.._url? – derDaywalker May 06 '15 at 10:08
  • This seems to be because you added a () wrapper around the :locale param, and then ruby is using it as an optional param instead of mandatory. removing the () might fix it or not. But that's a different question. The original one: how to fix it, seems to be answered. Feel free to upvote, mark or drink a beer on me. – Jorge de los Santos May 06 '15 at 12:19
  • It would be perfect if you edit your post to include the named hash. Then I will mark it as solution, because I can't mark your comment as solution. Once again, thx for your support and your solution! – derDaywalker May 06 '15 at 12:51
  • It was in the last part, but I've cleared the answer. – Jorge de los Santos May 06 '15 at 12:56