Rails duplicating requests - ruby-on-rails

After correcting some other bugs on the application I found out that one page is being rendered twice on every request.
Rails completes the request normally and after a few, simply starts another request.
At first thought it was a Firebug problem or YSlow doing other requests, but after more tests the duplication remained and I discarded those reasons.
I tried even debugging rails step by step in the request, it goes normally and after completing the first request, I get stopped in the same debugger start line again, this time for the second request.
Printed some lines and things to see clearly on log and it clearly makes 2 requests.
I also found a few wierd requests that I cannot explain also
This bit of log shows the end of the first request and right after that one, there is a wierd index request without layout and then the same request starts again to be processed:
Processing ArtistImagesController#index (for 192.168.0.11 at 2010-07-08 15:10:56) [GET]
Parameters: {"action"=>"index", "locale"=>"pt", "controller"=>"artist_images", "artist_id"=>"2-tom-welling"}
#^ Start of first request
#v end of first request
Completed in 812ms (View: 429, DB: 41) | 200 OK [http://192.168.0.20/artistas/2-tom-welling/imagens]
SQL (0.2ms) SET NAMES 'utf8'
SQL (0.2ms) SET SQL_AUTO_IS_NULL=0
# v wierd request
Processing ApplicationController#index (for 192.168.0.11 at 2010-07-08 15:10:59) [GET]
Rendering rescues/layout (not_found)
-----------------------------------------------------> html
SQL (0.2ms) SET NAMES 'utf8'
SQL (0.2ms) SET SQL_AUTO_IS_NULL=0
# v start of second request
Processing ArtistImagesController#index (for 192.168.0.11 at 2010-07-08 15:11:00) [GET]
Parameters: {"action"=>"index", "locale"=>"pt", "controller"=>"artist_images", "artist_id"=>"2-tom-welling"}
Remembering that all those requests were generated by entering the page only once :/
Searched the code for possible loops or any kind of errors but haven't found any.
Please help is very appretiated

Search your page source for empty image src attributes. For such images the browser requests the site root, which seems to be the case.

I think your page is submitting two times. can i view your page.

Related

What's the actual URL Rails generated for HTTP Verb PATCH?

Please bear with a newbie. I understand how Rails provides simple request with GET for simple URL links like localhost:3000/rooms/11/listing. The format is straight forward as stated in the Routes table. However I am confuse when it comes to PATCH, PUT, DELETE & CREATE. For example the output below, with params, was when I clicked SAVE button. My question, what's the actual URL that Rails generated when I clicked that SAVE button?
Started PATCH "/rooms/11" for 127.0.0.1 at 2019-08-20 05:25:32 +0800
(0.8ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
↳ /usr/local/rvm/gems/ruby-2.6.0/gems/activerecord-5.2.2/lib/active_record/log_subscriber.rb:98
Processing by RoomsController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"JHiCJ6HoTsgd8SGgLTFiZ9+J9hS9U8hHGvjKf4Lz3uieQ8OO2eFqFEM/D5xocHp/Nd3eA0az9k+okrmNe65BYg==", "room"=>{"home_type"=>"Apartment", "room_type"=>"Private", "accommodate"=>"3", "bed_room"=>"4", "bath_room"=>"3"}, "commit"=>"Save", "id"=>"11"}
I know from console
app.room_path(11)
=> "/rooms/11"
Is this Rails generated URL localhost:3000/rooms/11{"utf8"=>"✓", "authenticity_token"=>"JHiCJ6HoTsgd8SGgLTFiZ9+J9hS9U8hHGvjKf4Lz3uieQ8OO2eFqFEM/D5xocHp/Nd3eA0az9k+okrmNe65BYg==", "room"=>{"home_type"=>"Apartment", "room_type"=>"Private", "accommodate"=>"3", "bed_room"=>"4", "bath_room"=>"3"}, "commit"=>"Save", "id"=>"11"}?
No, the URL generated by app.room_path(11) is http://localhost:3000/rooms/11.
PATCH, PUT, DELETE and POST are called HTTP verbs. CREATE is not an HTTP verb.
One of these verbs goes along with your request, and Rails Router uses it to route the request to the correct Controller and Action.
Requests can have parameters, likes the one you showed here:
{"utf8"=>"✓", "authenticity_token"=>"JHiCJ6HoTsgd8SGgLTFiZ9+J9hS9U8hHGvjKf4Lz3uieQ8OO2eFqFEM/D5xocHp/Nd3eA0az9k+okrmNe65BYg==", "room"=>{"home_type"=>"Apartment", "room_type"=>"Private", "accommodate"=>"3", "bed_room"=>"4", "bath_room"=>"3"}, "commit"=>"Save", "id"=>"11"}
When you clicked on the Save button your browser requested http://localhost:3000/rooms/11 using the HTTP verb POST. The parameters were encoded on the body of the request.
A good place to learn more about this would be the Rails routing guide.
Here is the result from rake routes command. As you can see, GET, PATCH and PUT share the same generated URL (/rooms/:id, in your example /rooms/11). Since Rails 4.0, PATCH is the default verb to update action. Update action is triggered when you're sending a form to a route.

Persisting flash when a form is submitted multiple times

Background: I have essentially a multiple choice quiz. When a user submits a form, update scores their answer, chooses a new question, puts a message in the flash, and redirects back to the show action. show displays the message and the new question.
The immediate problem is that if they submit the form twice, update gets called twice. The first time scores their answer for the question they were given. The second time scores their answer for the question that was just now selected, which they haven't seen yet. So then they get redirected with a message saying something like "wrong! The answer is Spain, not Italy" When they had been choosing between Hydrogen and Helium.
So my first solution to this is to include a question_id field in the submitted form. If the submitted id isn't the id of the question that was asked, just ignore this request. This works for keeping track, but the message that was stored in the flash is lost.
So I've tried adding flash.keep if the ids don't match. My thinking is that one update will set the flash, and then the next request received will be the second update. But the flash is still getting lost. It seems that the second update doesn't start with a flash at all, which confuses me.
So my questions are: is there a better way to handle this problem? And if not, why is the flash disappearing?
update looks something like this (some lines omitted):
def update
game = current_user.credence_game
question = game.current_question
if params[:question_id].to_i == question.id
given_answer = params[:answer_index].to_i
credence = params[:credence].to_i
correct, score = question.score_answer(given_answer, credence)
game.score += score
game.new_question
game.save
flash[:correct] = correct
flash[:score] = score
flash[:message] = question.answer_message(given_answer)
else
flash.keep
end
redirect_to action: 'show'
end
If I add a p flash line just before redirect_to, the server spits out this:
#<ActionDispatch::Flash::FlashHash:0x007f2a8431b4a0 #used=#<Set: {}>, #closed=false, #flashes={:correct=>false, :score=>-32, :message=>"Incorrect. The right answer is White River (Arkansas) (1102km) versus Yellowstone River (1080km)."}, #now=nil>
Started PUT "/credence" for 127.0.0.1 at 2014-08-17 15:20:16 +0100
Processing by CredenceController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"EiqXDoFy77nmdKOE4YkHOeEFg4DvB5zdgFi98ynNCx0=", "question_id"=>"52", "credence"=>"60", "answer_index"=>"1", "commit"=>"60%"}
<Model stuff>
Redirected to http://localhost:3000/credence
Completed 302 Found in 667ms
#<ActionDispatch::Flash::FlashHash:0x000000059864f8 #used=#<Set: {}>, #closed=false, #flashes={}, #now=nil>
Started PUT "/credence" for 127.0.0.1 at 2014-08-17 15:20:18 +0100
Processing by CredenceController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"EiqXDoFy77nmdKOE4YkHOeEFg4DvB5zdgFi98ynNCx0=", "question_id"=>"52", "credence"=>"70", "answer_index"=>"1", "commit"=>"70%"}
<Model stuff, just loading the game and the question>
Redirected to http://localhost:3000/credence
Completed 302 Found in 421ms
Started GET "/credence" for 127.0.0.1 at 2014-08-17 15:20:19 +0100
Processing by CredenceController#show as HTML
<Model stuff>
Rendered layouts/_messages.html.erb (400.4ms)
Completed 200 OK in 963ms (Views: 776.4ms | ActiveRecord: 27.7ms)
<GET requests for CSS, images, etc.>
So it does seem like the first request after the flash is set, is the one where I'm calling flash.keep, but it still doesn't have the flash.
Edit: I'm realising the problem is likely that I'm using CookieStore. The first request doesn't get a chance to set cookies before the second request is sent. Using the session instead of flash would have the same issue.
A simple solution here, that I don't much like, would be to simply disable the forms with javascript onsubmit. A more complicated one would be: when the question ids don't match, look up the answer that the user gave for the submitted question id, and set the flash appropriately without changing the score.
Any alternatives?

Figuring out which element triggered request

I am currently working on a large project developed by 5 people.
The problem is that every time I load a particular page, I get a stray POST request along with the GET request for the page. The page contains no forms though a fair amount a jquery has been used.
Started POST "/my_profile" for 127.0.0.1 at 2012-03-06 21:34:23 +0530
ActionController::RoutingError (No route matches "/my_profile"):
Is there a way to find out which element or script triggered this POST request other than going through the entire code which is divided into 20 partials and 2 javascripts ?
If you're using Firefox, check out the Firebug plugin. The net panel will allow you to easily track down any POST / GET requests for a given page load.
You might try [binding_of_caller][1], caller or possibly [set_trace_func][2].
Dzone Snippets offers a robust way of using caller:
def caller_method_name
parse_caller(caller(2).first).last
end
def parse_caller(at)
if /^(.+?):(\d+)(?::in `(.*)')?/ =~ at
file = Regexp.last_match[1]
line = Regexp.last_match[2].to_i
method = Regexp.last_match[3]
[file, line, method]
end
end
Or you could do caller.inspect and just look at the raw output.
Binding_of_caller is a bit more involved and may be overkill for what you want but check it out if caller is not what you need. Same with set_trace_func.

protect_from_forgery does not protect PUT/DELETE requests

I made a demo application with rails new demo and then generated a scaffolded user controller with rails generate scaffold User name:string email:string. The scaffolded code has an ApplicationController with protect_from_forgery, so does UserController which derives from ApplicationController.
I run webrick, add a user, cool. Authenticity token works as promised with the POST on /users.
Yet still with Rails 3.0.5 I am able to do a:
niedakh#twettek-laptop:~$ telnet 10.0.0.4 3000
PUT /users/3 HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 39
user[name]=vvvvv&user[email]=shiaus.pl
And have the user 3 modified without giving a token:
Started PUT "/users/3" for 10.0.0.4 at 2011-04-02 14:51:24 +0200
Processing by UsersController#update as HTML
Parameters: {"user"=>{"name"=>"vvvvv", "email"=>"shiaus.pl\r"}, "id"=>"3"}
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
', "updated_at" = '2011-04-02 12:51:24.437267' WHERE "users"."id" = 3s.pl
Redirected to http://10.0.0.4:3000/users/3
Completed 302 Found in 92ms
Also I can do the same with DELETE:
DELETE /users/3 HTTP/1.1
Which gives me:
Started DELETE "/users/3" for 10.0.0.4 at 2011-04-02 15:43:30 +0200
Processing by UsersController#destroy as HTML
Parameters: {"id"=>"3"}
SQL (0.7ms) SELECT name
FROM sqlite_master
WHERE type = 'table' AND NOT name = 'sqlite_sequence'
User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 LIMIT 1
AREL (0.5ms) DELETE FROM "users" WHERE "users"."id" = 3
Redirected to http://10.0.0.4:3000/users
Completed 302 Found in 180ms
Could you explain to me why can I do those things when I never send any token alongside those requests?
Very Short Version: protect_from_forgery is designed to protect against XSRF attacks from forged HTML FORM elements. PUT and DELETE are not vulnerable to XSRF attacks because HTML forms cannot use PUT or DELETE.
An XSRF (cross site request forgery) attack is where the victim browser is tricked into submitting a forged request to the server without interaction from the user.
Longer version: The reason you are able to do this is you either:
Have no security/login required, or
Have already logged in and are making the requests from script hosted on the same domain, or
Are making the requests via Fiddler or similar, (bypassing the browser's built-in protections).
These are not the scenario protect_from_forgery is designed to protect against.
The purpose of the protect_from_forgery is to protect against XSRF attacks - Cross Site Request Forgery. This occurs when a user visiting an evil website (or a good website with added evil) is tricked into submitting a request to another website. For example you can trick a visitor into making any GET request, like this:
<img src="http://victim.com/victimPage?action=delete&id=ID12345" />
As soon as the victim visits the Evil site, his browser will automatically attempt to retrieve the image. This will obviously not retrieve an image, but meanwhile victim.com will execute the request deleting item ID12345. POST can be forged in a similar way, just create a form, and submit it to the foreign site using script, or else trick the user into clicking on it to submit.
That is where protect_from_forgery comes in: The server sends the token to the client in a hidden field with the form. If no valid token appears, the server concludes that the form which was submitted isn't a submission of a genuine form sent by the server, so the request is rejected as potentially forged.
But you knew that.
The point is that HTTP forms can only use methods GET and POST, not PUT or DELETE. This has two effects:
First, if you get a PUT or DELETE, there is nowhere to put the protect_from_forgery token. PUT or DELETE are not the result of a form submitting, so there is no way for the server to send the token to the client, therefore the client has no token to send back.
Second, since HTML forms can only use POST and GET, if the request is a PUT or DELETE the attacker cannot use a HTML form to force or trick the user into submitting the request. They can use XMLHttpRequest, but XMLHttpRequest does not allow cross-site requests (unless enabled by security settings on both sites).
This means that, provided the domain you host it on does not contain evil code itself, it is not necessary to protect PUT and DELETE from forgery. If the server does contain evil code, the attacker can make arbitrary XMLHttpRequest requests to get a valid token, and therefore easily circumvent the forgery protection anyway.
For a quick description of XSRF try here:
http://blogs.msdn.com/b/bryansul/archive/2008/08/15/rest-and-xsrf-part-one.aspx

AuthLogic one time password (persistence_token) - what config is required to use this?

Can anyone confirm what config exactly is required to make the one time password (persistence_token) work?
From what I can work out so far it is the following, however this isn't working for me so I must be wrong:
pass an additional URL parameter of "user_credentials=xxxxpersistence_tokenxxxx"
question - are there any other URL parameters required beyond this? any user id or username?
have the persistence_token field in my database table (which it is and I can see it populated)
have "acts _as _authentic " in my user model per normal
question: is "acts _as _authentic " required in each of my own models?
When I enter a URL in the browser directly to one of my own model resources following the above I see in the logs:
(a) initial request - Redirected to http://localhost:3000/user_session/new
(b) and then for this redirect:
Processing UserSessionsController#new (for 127.0.0.1 at 2009-12-03
06:14:24) [GET]
Parameters: {"action"=>"new", "controller"=>"user_sessions"}
User Columns (3.4ms) SHOW FIELDS FROM `users`
User Indexes (0.9ms) SHOW KEYS FROM `users`
Rendering template within layouts/application
Rendering user_sessions/new
SQL (0.6ms) SELECT count(*) AS count_all FROM `users` WHERE
(last_request_at > '2009-12-02 20:04:24')
Completed in 182ms (View: 151, DB: 5) | 200 OK [http://localhost/
user_session/new]
(c) But then the web-page ends up on the login page, and not
automatically on the page I was after - i.e. I was expecting that the
one-time password would allow AuthLogic to automatically do the
session and then authentication?
Thanks
PS. Wonder if it related to this authlogic code I found in params.rb
def single_access_allowed_request_types(value = nil)
rw_config(:single_access_allowed_request_types, value, ["application/rss+xml", "application/atom+xml"])
end
I think I have have it now. I did:
Pass the parameter (not header) of user_credentials=<>
Have the single_access_token column in your users table
Put the following method in the users_controller:
private
def single_access_allowed?
true
end
For other controllers (i.e. besides application, user, user_sessions)
I put: "before_filter :require_user" (not sure if there's a way to do this in the
controller that would handle it automatically?)
thanks

Resources