derDaywalker derDaywalker - 1 month ago 18
Ruby Question

rails I18n wrong parameter order in route (id as locale and id is nil)

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.

Answer

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.

Comments