Rails 3 Occasional Routing Error - ruby-on-rails

I'm running Rails 3.1.1 and getting an odd bug. In development (haven't yet tried pushing to production with it) I'm occasionally getting routing errors in my controller or in my mailer template when it tries to generate a url for a newly created record. This happens even though the record is created successfully and appears to have nothing to do with the record properties (I can recreate a record with the exact same params right after and not get the error, it seems totally random when it happens).
It seems to happen maybe one in 10 times, though I can't say I ever saw an incident of it happening before I added the mailer action.
There's one more potentially complicating factor: I'm using an encryption method to obfuscate the record's id in its URL, but this is otherwise working without a hitch. To do this I adapted the method discussed here
It seems to me like the URL's not generated in time for the link_to call some of the time... But that doesn't make much sense to me. I didn't think race conditions were something I needed to worry about here.
Here are my error logs when this happens in the controller (when the params don't call for an email to be generated):
ActionController::RoutingError (No route matches {:action=>"show", :controller=>"watch_lists", :id=>#<WatchList id: 195, title: "sfdsfd", created_at: "2012-03-19 05:18:46", updated_at: "2012-03-19 05:18:46", public_list: false>}):
app/controllers/watch_lists_controller.rb:72:in `block (2 levels) in create'
app/controllers/watch_lists_controller.rb:56:in `create'
And here's when it happens in the mailer template (when the params do call for an email to be generated before the render command):
Rendered watch_list_mailer/share_notification.html.erb (3.2ms)
Completed 500 Internal Server Error in 113ms
ActionView::Template::Error (No route matches {:action=>"show", :controller=>"watch_lists", :id=>#<WatchList id: 210, title: "sdggsgsg", created_at: "2012-03-19 05:47:17", updated_at: "2012-03-19 05:47:17", public_list: true>}):
20: <% end %>
21: <% end %><br>
22: <br>
23: Here's a link to your WatchList: <%= link_to #wl.title, watch_list_url(#wl) %><br>
24: <br>
25: Enjoy!
26: </p>
app/views/watch_list_mailer/share_notification.html.erb:23:in `_app_views_watch_list_mailer_share_notification_html_erb___1391186431365383285_70156615518000'
app/mailers/watch_list_mailer.rb:12:in `share_notification'
app/controllers/watch_lists_controller.rb:124:in `share_notification'
app/controllers/watch_lists_controller.rb:68:in `block (2 levels) in create'
app/controllers/watch_lists_controller.rb:63:in `each'
app/controllers/watch_lists_controller.rb:63:in `block in create'
app/controllers/watch_lists_controller.rb:56:in `create'
EDIT: Upon further testing, this appears to happen regardless of whether I include the mail task. It seems most likely spurred by the obfuscation of the links. It's possible that the encoding of the links has something to do with it (I had to make sure to URI-escape them to prevent slashes in the wrong places elsewhere in my code). I'll investigate this futher and report back.

It was a problem with the id encryption creating invalid links occasionally and me failing to account for that in early enough in the process.
In lib/obfuscate.rb
def uri_encrypt(value)
URI.escape(self.encrypt(value), Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
end
In my model
def to_param
uri_encrypt(id)
end

Related

"ActionController::InvalidAuthenticityToken" error when using form_with

I have a form that looks like this:
<%= form_with(url: star.starname, method: :post, local: true) do |f| %>
<% star.availabilities.each do |avail| %>
<%= f.label avail.time_slot %>
<%= radio_button_tag(:time_slot, avail.time_slot) %> <br>
<% end %>
<%= f.submit "Create" %>
<% end %>
Immediately after form submission:
Notes:
This is occurring in an app (not an API), so sessions are important, hence CSRF protection must be left on.
The problem occurs in chrome, incognito, and safari.
I have tried logging in with different users and clearing cookies (in case it was being caused by a stale token)
Some more of the error message:
Started POST "/talljohn" for ::1 at 2020-09-16 10:06:21 +1000
Processing by StarsController#book as HTML
Parameters: {"authenticity_token"=>"P++4a+giwUBqZgCLfMwqKpMu0EGitd8zTOi5RWsnxpKlNcjiuU6hd3ebbIC/IOxlL74RJIvrq+yDuA1ZtfcvFw==", "time_slot"=>"2020-09-16 01:00:00 UTC", "commit"=>"Create", "starname"=>"talljohn"}
Can't verify CSRF token authenticity.
Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms | Allocations: 655)
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
actionpack (6.0.3.2) lib/action_controller/metal/request_forgery_protection.rb:215:in `handle_unverified_request'
actionpack (6.0.3.2) lib/action_controller/metal/request_forgery_protection.rb:247:in `handle_unverified_request'
devise (4.7.2) lib/devise/controllers/helpers.rb:255:in `handle_unverified_request'
actionpack (6.0.3.2) lib/action_controller/metal/request_forgery_protection.rb:242:in `verify_authenticity_token'
activesupport (6.0.3.2) lib/active_support/callbacks.rb:428:in `block in make_lambda'
activesupport (6.0.3.2) lib/active_support/callbacks.rb:200:in `block (2 levels) in halting'
actionpack (6.0.3.2) lib/abstract_controller/callbacks.rb:34:in `block (2 levels) in <module:Callbacks>'
activesupport (6.0.3.2) lib/active_support/callbacks.rb:201:in `block in halting'
Update
I reverted back to the last working version of the form, which was exactly the same as above but without , local: true. Then it suddenly works! (no errors).
I thought local: true (or remote: false) simply turns off ajax form submission. So I don't understand why that would make any difference (or have anything to do with CSRF), it seems that those two aspects are unrelated and it isn't clear why these two concepts would have any affect on eachother
Update 2
I later realised that another untouched previously working form also produced this error. It had not been changed in any way. I tried it in chrome incognito, and it produced the error. Half an hour later (without changing any code) I tried it again in the same browser and it worked. This (very) strange behaviour makes me think it's something to do with sessions, cookies or caching. I will report back if I learn anything further
Update 3
After reading Sarah's solution adding protect_from_forgery prepend: true to the application controller (I tried both before and after before_action :authenticate_user!), the same error message appears in the logs, the POST request isn't actioned, but the app redirects to the home page. I.e. upon POST I see:
Can't verify CSRF token authenticity.
Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms | Allocations: 444)
Started GET "/users/sign_in" for ::1 at 2020-09-17 21:08:42 +1000
Processing by Devise::SessionsController#new as HTML
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
Redirected to http://localhost:3000/
Filter chain halted as :require_no_authentication rendered or redirected
Completed 302 Found in 3ms (ActiveRecord: 0.5ms | Allocations: 1900)
Update 4
I attempted to manually clear the rails fragment cache (with Rails.cache.clear ). But the result is exactly the same before/after clearing the fragment cache.
I remember running into something like this and adding protect_from_forgery prepend: true before any user authentication to the ApplicationController solved it.
TL;DR: after 2 weeks' of debugging attempts, I turned off turbolinks and the problem went away.
Aside from turning off turbolinks, another solution appears to be (mentioned here) adding this to application.js
$(document).on('turbolinks:load', function(){ $.rails.refreshCSRFTokens(); });
Previous answer
The issue kept reemerging. I have tried the following six things but it still hasn't fixed it
1. Clear the fragment cache
Rails.cache.clear (warning because it clears the cache, it will also remove things like sidekiq jobs etc). This will remove the stale token and refreshing the app in the browser will return things to normal, and the form should submit (a simple 'resubmit' won't work, so go back to the form page, refresh, then submit and it should work)
2. Hard refresh page
Press cmd + opt + j to bring up the developer console, then right click on refresh and select 'Empty Cache and Hard Reload'
3. Delete site cookies
Right click on the tiny icon to the immediate left of the url (it will be a lock if using https, or the letter 'i' if using http). Go into each of categories listed (e.g. 'Cookies', 'Site Settings' etc) and delete them all
4. Delete cookies for other urls that point to the same site
For example, if your site is www.example.com, and it's hosted on heroku at www.example.herokuapp.com, then delete cookies for that second url as well
5. Delete cookies for localhost
I deleted localhost cookies just to be sure
6. Testing in completely isolated instances of chrome
For me, the solution was to switch to a more specific Cookie Strategy:
# config/initializers/new_framework_defaults_6_1.rb
# Before: i've used None, but this leads to broken Cookies somehow. Strict or Lax seems to work.
Rails.application.config.action_dispatch.cookies_same_site_protection = :strict

Impossible to delete a flash

I made a mistake before migrating a plugin, and have written
flash[:notice] = :label_presta_added
instead of
flash[:notice] = l(:label_presta_added)
I corrected my mistake but it seems that my Redmine Plugin has trashed my Redmine. Even though I delete my plugin a migrate once again, I still get this error:
Started GET "/" for 127.0.0.1 at 2016-06-01 22:21:37 +0200
Processing by WelcomeController#index as HTML
Current user: admin (id=1)
Rendered welcome/index.html.erb within layouts/base (28.1ms)
Completed 500 Internal Server Error in 366ms (ActiveRecord: 116.0ms)
ActionView::Template::Error (undefined method `html_safe' for :label_presta_added:Symbol
Did you mean? html_safe?):
97: <div id="sidebar">
98: <%= yield :sidebar %>
99: <%= view_layouts_base_sidebar_hook_response %>
100: </div>
101:
102: <div id="content">
103: <%= render_flash_messages %>
app/helpers/application_helper.rb:312:in `block in render_flash_messages'
app/helpers/application_helper.rb:311:in `render_flash_messages'
app/views/layouts/base.html.erb:100:in `_app_views_layouts_base_html_erb__4104276684161420982_39604440'
lib/redmine/sudo_mode.rb:63:in `sudo_mode'
Can somebody give me a hand here?
Thanks in advance!
This is stored in your session, so usually changing the session secret key will invalidate all sessions and discard any old session data.
You can also try and rescue to clear it out as a one-time deal.
Have you restarted the server? Or you can use flash[:notice] = nil to remove it.
It looks like it throws a html_safe error. Can you see if the method which is rendering the flash is using html_safe? It looks like its coming from there.
Not sure exactly, may be shooting in the dark.
But read these and try may be:
actionview::template::error(undefined method 'html_safe' for nil:NilClass)
http://www.redmine.org/issues/8477

current_user available when using firefox but not Chrome

I am using Rails and Devise in a Rails application.
In my code, I am trying to use current_user in layouts/_header.html.erb.
<% Rails.logger.debug("Time is: #{Time.now} - Current User: #{current_user}") %>
When I use Firefox on my MAC to run the application, here's what I have in the log file:
Time is: 2013-06-18 16:21:42 - Current User: #<User:0x007fae442cf020>
When I use Chrome on my MAC to run the application, here's what I have in the log file:
Time is: 2013-06-18 16:20:33 - Current User:
Rendered layouts/_promo_bar.html.erb (3.4ms)
Completed 500 Internal Server Error in 657ms
ActionView::Template::Error (undefined method `email' for nil:NilClass):
27: <div class="promo-bar-box last-right-box">
28: <div class="request-invitation-text">
29: <% Rails.logger.debug("Time is: #{Time.now} - Current User: #{current_user}") %>
30: <% reg_user = user_registered_for_event(current_user.email) %>
app/views/layouts/_promo_bar.html.erb:30:in `_app_views_layouts__promo_bar_html_erb__785786602602486184_70193263335300'
Any ideas?
It looks like you are accessing a page without having logged in yet. If the session isn't set then current_user isn't going to exist and throw an error when trying to access one of its attributes, in this case being the user's email.
If you are logged in, try clearing your session cookie via Devloper Tools (hamburger icon > tools > Developer Tools). And reloading the page.

NoMethodError in Human_resources/leaves#index

It was working few days ago, don't know what had went wrong...
**undefined method `name' for nil:NilClass**
Extracted source (around line #26):
23: %td= number_with_precision(employee.compensation_leave_balance, precision:1)
24: #calendar.tab-pane.fade
25: = calendar(:year => 2012, :month => 6, :first_day_of_week => 1, summary: "Leave Calendar", calendar_title: "June", month_header: true) do |date|
26: - render_leave_calendar_cell(date)
27: #trash.tab-pane.fade
28: = render 'table', leaves: #leaves.where(deleted: true)
app/helpers/leaves_helper.rb:11:in `block in events_for'
app/helpers/leaves_helper.rb:10:in `events_for'
app/helpers/leaves_helper.rb:4:in `render_leave_calendar_cell'
app/views/human_resources/leaves/index.html.haml:26:in `block in _app_views_human_resources_leaves_index_html_haml__145883348_88978910'
app/helpers/calendar_helper.rb:146:in `call'
app/helpers/calendar_helper.rb:146:in `block in calendar'
app/helpers/calendar_helper.rb:145:in `upto'
app/helpers/calendar_helper.rb:145:in `calendar'
app/views/human_resources/leaves/index.html.haml:25:in `_app_views_human_resources_leaves_index_html_haml__145883348_88978910'
really don't know what went wrong
a/h/leaves_helper.rb
1 module LeavesHelper
2 def render_leave_calendar_cell(date)
3 html = content_tag(:span, date.day, class: 'dayDisplay')
4 html += content_tag(:div, events_for(date))
5 raw(html)
6 end
7
8 def events_for(date)
9 html = ""
10 current_company.leaves.where("start_date <= '#{date}' and return_date > '#{date}'").where(deleted: false).each do |leave|
11 html += content_tag(:div, leave.applicant.name, class: 'leaveName')
12 end
13 raw html
14 end
could it be the date nil? how to fix this ><
much appreciate
Billy
as abhas already stated, leave.applicant is nil for at least one of the leaves.
go to your database and find out which it is. then figure out what to do with your leaves. delete them too, re-add the missing applicant or what ever data migration might be sensible.
a quick fix would be to skip if an applicant is missing:
html += content_tag(:div, leave.applicant.name, class: 'leaveName') if leave.applicant.present?
i would also have a look if you properly configured the delete cascades in your application. this often causes such problems. if you want to enforce safety in this regard, you should add database constraints, that ensure that no referenced entity gets deleted.

Facebooker Gem Session Key Expired

My Facebook Connect Rails application worked earlier today, but seems to have stopped getting the Facebook sessions properly.
I'm using the Facebooker gem to handle the interaction with Facebook. All of a sudden, my application started throwing this exception, both while I was logged in to my Facebook account and while I was logged out (on the actual Facebook site):
WelcomeController#index (ActionView::TemplateError) "Session key invalid or no longer valid"
On line #4 of app/views/welcome/_friends.html.erb
1: <div class="bluebox friends_box">
2: <h3>Friends</h3>
3: <table class="friends_table">
4: <% friends = facebook_user.friends_with_this_app %>
5: <% if friends.any? %>
6: <% friends.each do |friend| %>
7: <tr class="friend_row">
app/views/welcome/_friends.html.erb:4
app/views/welcome/_logged_in_index.html.erb:90
app/views/welcome/index.html.erb:2
<internal:prelude>:8:in `synchronize'
<internal:prelude>:8:in `synchronize'
First of all, make sure that your app is authorized with Facebook by going to the following address in the browser window where you got the exception:
http://www.facebook.com/login.php?api_key=YOUR_APP_KEY&next=RETURN_URL
If you're getting the error after that, more than likely, it has to do with Facebook itself. Sometimes it helps to get the session key out of cookie ("YOUR_APP_KEY" + "_session_key" cookie), but sometimes it doesn't work either.

Resources