undefined method `password_confirmation=' rails 5 - ruby-on-rails

I have ruby on rails API
So far the logic is to devise password reset
here is code block for finding User and resting password
def update_password_by_token
#user = User.find_by_reset_password_token!(params[:id])
if #user.reset_password_sent_at < 2.hours.ago
render status: 422, json: {}
else
#user.password = params[:password]
#user.password_confirmation = params[:confirm_password]
if #user.save
render status: 200, json: {}
else
render status: 422, json: {}
end
end
end
here is android sending params to API
{
"password":"newpassword",
"confirm_password":"newpassword",
"id":"Upn0QHKNy858yMK1J8x1KA"
}
So digging deeper I took the token and fire up the rails console.
#user = User.find_by_reset_password_token!("Upn0QHKNy858yMK1J8x1KA")
User Load (1.5ms) SELECT "users".* FROM "users" WHERE
"users"."deleted_at" IS NULL AND "users"."reset_password_token" = $1
LIMIT $2 [["reset_password_token", "CtW8XFYUdX3d9J7H1rtfUQ"], ["LIMIT",
1]]
=> #<User id: 57, first_name: "abc", last_name: "def", email:
"kalamasher#gmail.com", deleted_at: nil, authentication_token:
"uTWmP41bgihmSW-Thsog", created_at: "2019-01-10 09:56:30", updated_at:
"2019-01-10 10:33:07", is_confirmed: true, firebase_token:
"caQkNMlpp2s:APA91bEr4NKSKsMJ-VCJaXLd8mxadb7...", tenant_id: 6,
is_admin: false, mobile_device: "android", user_level: "partner">
irb(main):006:0> #user.password ="new#password"
=> "new#password"
irb(main):007:0> #user.password_confirmation ="new#password"
=> "new#password"
irb(main):008:0> #user.save
(2.7ms) BEGIN
User Exists (1.6ms) SELECT 1 AS one FROM "users" WHERE "users"."email"
= $1 AND "users"."deleted_at" IS NULL AND ("users"."id" != $2) AND
"users"."tenant_id" = $3 LIMIT $4 [["email", "kalamasher#gmail.com"],
["id", 57], ["tenant_id", 6], ["LIMIT", 1]]
SQL (1.6ms) UPDATE "users" SET "encrypted_password" = $1,
"reset_password_token" = $2, "reset_password_sent_at" = $3, "updated_at"
= $4 WHERE "users"."id" = $5 [["encrypted_password",
"$2a$10$pRhNupGtOiCeCafNsdiVYuqTNYNZqI.xa2oyGmkRIybmDiYOR.f0i"],
["reset_password_token", nil], ["reset_password_sent_at", nil],
["updated_at", "2019-01-10 11:08:46.354276"], ["id", 57]]
(2.4ms) COMMIT
=> true
Updation
A NoMethodError occurred in members#update_password_by_token:
undefined method `password_confirmation=' for nil:NilClass
app/controllers/api/v1/members_controller.rb:85:in `update_password_by_token'
-------------------------------
Request:
-------------------------------
* URL : http:#####/api/members/update_password_by_token
* HTTP Method: POST
* IP address : X.X.X.X
* Parameters : {"password"=>"[FILTERED]", "confirm_password"=>"[FILTERED]", "id"=>"CtW8XFYUdX3d9J7H1rtfUQ", "format"=>"json", "controller"=>"api/v1/members", "action"=>"update_password_by_token"}
* Timestamp : 2019-01-10 10:33:55 UTC
* Server : oacsrv01
* Rails root : releases/20180531092251
* Process: 3967
-------------------------------
Session:
-------------------------------
* session id: nil
* data: {}
-------------------------------
Environment:
-------------------------------
* CONTENT_LENGTH : 75
* CONTENT_TYPE : application/x-www-form-urlencoded
* HTTP_ACCEPT : application/json, text/plain, */*
* HTTP_ACCEPT_ENCODING : gzip, deflate
* HTTP_ACCEPT_LANGUAGE : en-US,en;q=0.9,la;q=0.8
* HTTP_CONNECTION : close
* HTTP_DNT : 1
* HTTP_HOST : host
* HTTP_ORIGIN : http:
* HTTP_REFERER : http:
* HTTP_USER_AGENT : Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36
* HTTP_VERSION : HTTP/1.0
* HTTP_X_FORWARDED_FOR : X.X.X.X
* ORIGINAL_FULLPATH : /api/members/update_password_by_token
* ORIGINAL_SCRIPT_NAME :
* PATH_INFO : /api/members/update_password_by_token
* QUERY_STRING :
* REMOTE_ADDR : 127.0.0.1
* REQUEST_METHOD : POST
* REQUEST_PATH : /api/members/update_password_by_token
* REQUEST_URI : /api/members/update_password_by_token
* ROUTES_47174199350780_SCRIPT_NAME :
* SCRIPT_NAME :
* SERVER_NAME : server*****
* SERVER_PORT : 80
* SERVER_PROTOCOL : HTTP/1.0
* SERVER_SOFTWARE : Unicorn 5.3.1
* action_controller.instance : #<Api::V1::MembersController:0x0055cf355102c0>
* action_dispatch.backtrace_cleaner : #<Rails::BacktraceCleaner:0x0055cf347bec20>
* action_dispatch.cookies : #<ActionController::RequestForgeryProtection::ProtectionMethods::NullSession::NullCookieJar:0x0055cf3553aea8>
* action_dispatch.cookies_digest :
* action_dispatch.cookies_serializer : json
* action_dispatch.encrypted_cookie_salt : encrypted cookie
* action_dispatch.encrypted_signed_cookie_salt : signed encrypted cookie
* action_dispatch.http_auth_salt : http authentication
* action_dispatch.key_generator : #<ActiveSupport::CachingKeyGenerator:0x0055cf32a45810>
* action_dispatch.logger : #<ActiveSupport::Logger:0x0055cf32b27e68>
* action_dispatch.parameter_filter : [:password]
* action_dispatch.redirect_filter : []
* action_dispatch.remote_ip : X.X.X.X
* action_dispatch.request.content_type : application/x-www-form-urlencoded
* action_dispatch.request.flash_hash :
* action_dispatch.request.formats : [#<Mime::Type:0x0055cf31200390 #synonyms=["text/x-json", "application/jsonrequest"], #symbol=:json, #string="application/json", #hash=-2441761977289553219>]
* action_dispatch.request.parameters : {"password"=>"[FILTERED]", "confirm_password"=>"[FILTERED]", "id"=>"CtW8XFYUdX3d9J7H1rtfUQ", "format"=>"json", "controller"=>"api/v1/members", "action"=>"update_password_by_token"}
* action_dispatch.request.path_parameters : {:format=>"json", :controller=>"api/v1/members", :action=>"update_password_by_token"}
* action_dispatch.request.query_parameters : {}
* action_dispatch.request.request_parameters : {"password"=>"[FILTERED]", "confirm_password"=>"[FILTERED]", "id"=>"CtW8XFYUdX3d9J7H1rtfUQ"}
* action_dispatch.request.unsigned_session_cookie: {}
* action_dispatch.request_id : efb6377f-4437-46c5-8e13-5cc40b79692f
* action_dispatch.routes : #<ActionDispatch::Routing::RouteSet:0x0055cf32ca2bf8>
* action_dispatch.secret_key_base : 0a1d165e12a2bc249fdd588b275f670198835b689324af3b36e8b9ab4fe246ec80c97c1cb6d3ba495c7d214a06eb3285f25081ce6d307d520a9c0a6bdd892872
* action_dispatch.secret_token :
* action_dispatch.show_detailed_exceptions : false
* action_dispatch.show_exceptions : true
* action_dispatch.signed_cookie_salt : signed cookie
* devise.skip_storage : true
* rack.cors : #<Rack::Cors::Result:0x0055cf35476f08>
* rack.errors : #<File:0x0055cf2f25d538>
* rack.hijack : #<Unicorn::HttpParser:0x0055cf3003b3d0>
* rack.hijack? : true
* rack.input : #<Unicorn::TeeInput:0x0055cf35421b98>
* rack.logger : #<Logger:0x0055cf2fd86810>
* rack.multiprocess : true
* rack.multithread : false
* rack.request.cookie_hash : {}
* rack.request.form_hash : {"password"=>"[FILTERED]", "confirm_password"=>"[FILTERED]", "id"=>"CtW8XFYUdX3d9J7H1rtfUQ"}
* rack.request.form_input : #<Unicorn::TeeInput:0x0055cf35421b98>
* rack.request.form_vars : [FILTERED]
* rack.request.query_hash : {}
* rack.request.query_string :
* rack.run_once : false
* rack.session : #<ActionController::RequestForgeryProtection::ProtectionMethods::NullSession::NullSessionHash:0x0055cf3553af48>
* rack.session.options : {:skip=>true}
* rack.tempfiles : []
* rack.url_scheme : http
* rack.version : [1, 2]
* unicorn.socket : #<Kgio::Socket:0x0055cf35421e90>
* warden : Warden::Proxy:47174220233180 #config={:default_scope=>:user, :scope_defaults=>{}, :default_strategies=>{:user=>[:rememberable, :database_authenticatable]}, :intercept_401=>false, :failure_app=>#<Devise::Delegator:0x0055cf2fedcd18>}
-------------------------------
Backtrace:
-------------------------------
app/controllers/api/v1/members_controller.rb:85:in `update_password_by_token'
F, [2019-01-10T15:33:56.326625 #3967] FATAL -- : [efb6377f-4437-46c5-8e13-5cc40b79692f]
F, [2019-01-10T15:33:56.326751 #3967] FATAL -- : [efb6377f-4437-46c5-8e13-5cc40b79692f] NoMethodError (undefined method `password_confirmation=' for nil:NilClass):
F, [2019-01-10T15:33:56.326796 #3967] FATAL -- : [efb6377f-4437-46c5-8e13-5cc40b79692f]
F, [2019-01-10T15:33:56.327032 #3967] FATAL -- : [efb6377f-4437-46c5-8e13-5cc40b79692f] app/controllers/api/v1/members_controller.rb:85:in `update_password_by_token'
am I doing something wrong in the deployed code.
Anyone Please advise
thanks in advance

Check your User model has password_digest attribute. password_confirmation method require your User model has a password_digest attribute.
In order to use this method, in your User model, add has_secure_password method as follow,
class User < ApplicationRecord
has_secure_password
end
has_secure_password method will add password_digest attribute if your User model has password_digest.
Fyi, below is part of secure_password.rb in ActiveModel
module ClassMethods
# Adds methods to set and authenticate against a BCrypt password.
# This mechanism requires you to have a +password_digest+ attribute.
#
# The following validations are added automatically:
# * Password must be present on creation
# * Password length should be less than or equal to 72 bytes
# * Confirmation of password (using a +password_confirmation+ attribute)
#
# If password confirmation validation is not needed, simply leave out the
# value for +password_confirmation+ (i.e. don't provide a form field for
# it). When this attribute has a +nil+ value, the validation will not be
# triggered.

Finally after spending a day I sort it out and its working now.
The only solution was "excluding password_confirmation" from the function.
and now the updated code for password update_password_by_token function is as follows.
def update_password_by_token
#user = User.find_by_reset_password_token!(params[:id])
if #user.present?
if #user.reset_password_sent_at < 2.hours.ago
render status: 422, json: {}
else
#user.password = params[:password]
if #user.save
render status: 200, json: {}
else
render status: 422, json: {}
end
end
end
end
Once again Thanks to everybody who tried to help me in the context.
I posted the answer so it may help someone in the future.

Related

Swagger PHP - Describe array of objects

I use Laravel + Swagger PHP. In one of my services, I handle parameters like this :
$params = [
'addressChild' => [
'address' => ' ... ',
'city' => ' ... ',
],
'addressParent' => [
'address' => ' ... ',
'city' => ' ... ',
],
];
I am trying to describe this schema in Swagger Annotations, using OpenApi 3 :
/**
* #OA\Post(
* path="/entity/{entity}/addresses",
* #OA\Response(
* response=200,
* #OA\JsonContent()
* ),
* #OA\RequestBody(
* description="Addresses to store",
* required=true,
* #OA\JsonContent(
* type="object",
* #OA\Property()
* ),
* ),
* )
*
*/
public function update(Request $request)
{
// ...
}
I tried many things like :
#OA\JsonContent(
type="object",
#OA\Property(name="addressKid", ref="#/components/schemas/ParkingAddressRequest") // error
),
My address data is described in ref="#/components/schemas/ParkingAddressRequest" schema, how can I set it as an array in RequestBody ?
If I understood your problem, you could do it like this
/**
* #OA\Post(
* path="/entity/{entity}/addresses",
* #OA\Response(
* response=200,
* #OA\JsonContent()
* ),
* #OA\RequestBody(
* description="Addresses to store",
* required=true,
* #OA\JsonContent(
* type="array",
* #OA\Items(ref="#/components/schemas/ParkingAddressRequest")
* ),
* ),
* )
*
*/

Is there a simple way to calculate sumproduct in Rails?

I have a PositionGroup that has_many :positions.
Whenever a position_group object is touched, I would like to update pg.average_price like so:
# Average Price = ((position1.transaction_price * (position1.volume/total_volume) +
# position2.transaction_price * (position2.volume/total_volme))
In my callback method, I tried this:
def update_average_price
total_volume = positions.sum(:volume)
avg_price = positions.sum("transaction_price * (volume/#{total_volume})")
update_column(:average_price, avg_price)
end
But when I check the value of avg_price once multiple positions exist, I am getting 0.0.
This is my spec for this specific functionality:
it "should calculate the Weighted Average Purchase Price of all positions" do
# Position 3: Price = 20, volume = 200
# (Position 1 Price * (Position 1 Units/Total # of Units)) +
# (Position 2 Price * (Position 2 Units/Total # of Units)) +
# (Position 3 Price * (Position 3 Units/Total # of Units))
# ($10 * (100/400)) + ($15 * (100/400) + $20 * (100/400)) =
# ($2.50 + $3.75 + $5) = $11.25
price3 = 20
pos3 = create(:position, stock: stock, portfolio: portfolio, transaction_price: 20, current_price: price3, action: :buy, volume: 200, position_group: pg)
expect(pg.average_price).to eql 11.25
end
This is the result when I run it:
1) PositionGroup methods should calculate the Weighted Average Purchase Price of all positions
Failure/Error: expect(pg.average_price).to eql 11.25
expected: 11.25
got: 0.0
(compared using eql?)
I am pretty sure the issue is this line, from my callback method update_average_price on PositionGroup:
avg_price = positions.sum("transaction_price * (volume/#{total_volume})")
Is there a better way to approach this or is there something else giving me that 0.0 when I shouldn't be?
avg_price = positions.sum("transaction_price * (volume/#{total_volume.to_f})")
to_f is missing, converting to float to get a decimal to work with.
Example
irb(main):022:0> Position.all
Position Load (0.3ms) SELECT "positions".* FROM "positions" LIMIT ? [["LIMIT", 11]]
=> #<ActiveRecord::Relation [#<Position id: 1, transaction_price: 0.5e2, volume: 150, position_group_id: 1>, #<Position id: 2, transaction_price: 0.1e1, volume: 50, position_group_id: 1>]>
irb(main):023:0> Position.all.sum("transaction_price * (volume/#{total_volume.to_f})")
(0.2ms) SELECT SUM(transaction_price * (volume/200.0)) FROM "positions"
=> 37.75

Regular ActionController::InvalidAuthenticityToken exceptions - Rails

I have a Rails 4.2.6 app (also running Devise) in production with the Exception Notification gem installed and working. I get waves in hundreds of ActionController::InvalidAuthenticityToken errors (sample below), usually 2-3 per minute for hours at a time. I am not too clued up on the security side of Rails but I guess this is a robot attempting a CSRF attack of some form.
It always comes from the same IP address (107.15.69.216) which looks like one from Raleigh, North Carolina, USA.
Is it a robot?
And, Is there something I need to do about this or is the error simply proving that Devise's CSRF attack protection is working as it should?
An ActionController::InvalidAuthenticityToken occurred in registrations#create:
ActionController::InvalidAuthenticityToken
-------------------------------
Request:
-------------------------------
* URL : https://xxx.xxx.xxx.xxx/
* HTTP Method: POST
* IP address : 107.15.69.216
* Parameters : {"Q/Zcl9vJY8K1NPSRoHXnCQrZaPF8pu/uXVPyCfW8RnAQclIPvjOvpXqFLY TPUg9uBDmGWG5lMd8vzgSuGw79LAE d03xLFVtA/JUrX7cKmb3u Wrd7xS2LsMlSj2zAvtxmSPkGpoKR8e1p/XAQ exuiMte/fyXnLSrVjMfmzpNNxr7MSamyRHFVQan3LaxMJUq 02h4D1L4psFwbwl9k27W45G8FT9LaS2HG7g7y/rsxAon8ovLUgQNY2HcRMf7XlZxmxK20kDWfcLLn8DrpwY/bSW6mGsxAgD0CkapGj5LU7Smg5FvtR5qFn7q Ey9F0YdlMpE5/MqYWQNINgpzIxokxY1JyEdg5WphcGExuXjPDN3ChYUrkZG4h PAe7LuaGSQjyTOY/K4/O/iLODlBcM EqxCVZY8J04"=>nil, "controller"=>"registrations", "action"=>"create"}
* Timestamp : 2017-01-12 14:00:54 UTC
* Server : sgp1-iml-01
* Rails root : /home/app-name-deploy/apps/app-name/releases/20161212034105
* Process: 11031
-------------------------------
Session:
-------------------------------
* session id: [FILTERED]
* data: {}
-------------------------------
Environment:
-------------------------------
* CONTENT_LENGTH : 420
* CONTENT_TYPE : application/x-www-form-urlencoded
* GATEWAY_INTERFACE : CGI/1.2
* HTTP_CACHE_CONTROL : no-cache
* HTTP_CONNECTION : close
* HTTP_HOST : xxx.xxx.xxx.xxx
* HTTP_USER_AGENT : Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
* HTTP_VERSION : HTTP/1.0
* HTTP_X_FORWARDED_FOR : 107.15.69.216
* HTTP_X_FORWARDED_PROTO : https
* ORIGINAL_FULLPATH : /
* ORIGINAL_SCRIPT_NAME :
* PATH_INFO : /
* QUERY_STRING :
* REMOTE_ADDR : 127.0.0.1
* REQUEST_METHOD : POST
* REQUEST_PATH : /
* REQUEST_URI : /
* ROUTES_42047240_SCRIPT_NAME :
* SCRIPT_NAME :
* SERVER_NAME : xxx.xxx.xxx.xxx
* SERVER_PORT : 443
* SERVER_PROTOCOL : HTTP/1.1
* SERVER_SOFTWARE : puma 3.6.0 Sleepy Sunday Serenity
* action_controller.instance : #<RegistrationsController:0x00000006f6a0d0>
* action_dispatch.backtrace_cleaner : #<Rails::BacktraceCleaner:0x00000005458648>
* action_dispatch.cookies : #<ActionDispatch::Cookies::CookieJar:0x00000006f537b8>
* action_dispatch.cookies_digest :
* action_dispatch.cookies_serializer : json
* action_dispatch.encrypted_cookie_salt : encrypted cookie
* action_dispatch.encrypted_signed_cookie_salt : signed encrypted cookie
* action_dispatch.http_auth_salt : http authentication
* action_dispatch.key_generator : #<ActiveSupport::CachingKeyGenerator:0x00000006945560>
* action_dispatch.logger : #<ActiveSupport::Logger:0x00000006d22570>
* action_dispatch.parameter_filter : [:password]
* action_dispatch.redirect_filter : []
* action_dispatch.remote_ip : 107.15.69.216
* action_dispatch.request.content_type : application/x-www-form-urlencoded
* action_dispatch.request.formats : [#<Mime::Type:0x000000053404e0 #synonyms=["application/xhtml+xml"], #symbol=:html, #string="text/html", #hash=672552242721212245>]
* action_dispatch.request.parameters : {"Q/Zcl9vJY8K1NPSRoHXnCQrZaPF8pu/uXVPyCfW8RnAQclIPvjOvpXqFLY TPUg9uBDmGWG5lMd8vzgSuGw79LAE d03xLFVtA/JUrX7cKmb3u Wrd7xS2LsMlSj2zAvtxmSPkGpoKR8e1p/XAQ exuiMte/fyXnLSrVjMfmzpNNxr7MSamyRHFVQan3LaxMJUq 02h4D1L4psFwbwl9k27W45G8FT9LaS2HG7g7y/rsxAon8ovLUgQNY2HcRMf7XlZxmxK20kDWfcLLn8DrpwY/bSW6mGsxAgD0CkapGj5LU7Smg5FvtR5qFn7q Ey9F0YdlMpE5/MqYWQNINgpzIxokxY1JyEdg5WphcGExuXjPDN3ChYUrkZG4h PAe7LuaGSQjyTOY/K4/O/iLODlBcM EqxCVZY8J04"=>nil, "controller"=>"registrations", "action"=>"create"}
* action_dispatch.request.path_parameters : {:controller=>"registrations", :action=>"create"}
* action_dispatch.request.query_parameters : {}
* action_dispatch.request.request_parameters : {"Q/Zcl9vJY8K1NPSRoHXnCQrZaPF8pu/uXVPyCfW8RnAQclIPvjOvpXqFLY TPUg9uBDmGWG5lMd8vzgSuGw79LAE d03xLFVtA/JUrX7cKmb3u Wrd7xS2LsMlSj2zAvtxmSPkGpoKR8e1p/XAQ exuiMte/fyXnLSrVjMfmzpNNxr7MSamyRHFVQan3LaxMJUq 02h4D1L4psFwbwl9k27W45G8FT9LaS2HG7g7y/rsxAon8ovLUgQNY2HcRMf7XlZxmxK20kDWfcLLn8DrpwY/bSW6mGsxAgD0CkapGj5LU7Smg5FvtR5qFn7q Ey9F0YdlMpE5/MqYWQNINgpzIxokxY1JyEdg5WphcGExuXjPDN3ChYUrkZG4h PAe7LuaGSQjyTOY/K4/O/iLODlBcM EqxCVZY8J04"=>nil}
* action_dispatch.request.unsigned_session_cookie: {}
* action_dispatch.request_id : b8c1d2ef-0272-4e58-928d-8d02e8c5ad28
* action_dispatch.routes : #<ActionDispatch::Routing::RouteSet:0x00000005032e10>
* action_dispatch.secret_key_base : 72399ae7d71631b9bf5c19fe5e63e6e6c7163f37cdf8d1bb853cb77b53b6de0d20ce168a0e4a6fc87fadeb09b122a30d09ff9103f2f05a6bd5660c4c00f57392
* action_dispatch.secret_token :
* action_dispatch.show_detailed_exceptions : false
* action_dispatch.show_exceptions : true
* action_dispatch.signed_cookie_salt : signed cookie
* devise.mapping : #<Devise::Mapping:0x00000006939c60>
* puma.config : #<Puma::Configuration:0x00000002f1e940>
* puma.socket : #<UNIXSocket:0x00000006f768a8>
* rack.after_reply : []
* rack.errors : #<File:0x0000000230dac0>
* rack.hijack : #<Puma::Client:0x00000006f76880>
* rack.hijack? : true
* rack.input : #<StringIO:0x00000006f762b8>
* rack.multiprocess : false
* rack.multithread : true
* rack.request.cookie_hash : {}
* rack.request.form_hash : {"Q/Zcl9vJY8K1NPSRoHXnCQrZaPF8pu/uXVPyCfW8RnAQclIPvjOvpXqFLY TPUg9uBDmGWG5lMd8vzgSuGw79LAE d03xLFVtA/JUrX7cKmb3u Wrd7xS2LsMlSj2zAvtxmSPkGpoKR8e1p/XAQ exuiMte/fyXnLSrVjMfmzpNNxr7MSamyRHFVQan3LaxMJUq 02h4D1L4psFwbwl9k27W45G8FT9LaS2HG7g7y/rsxAon8ovLUgQNY2HcRMf7XlZxmxK20kDWfcLLn8DrpwY/bSW6mGsxAgD0CkapGj5LU7Smg5FvtR5qFn7q Ey9F0YdlMpE5/MqYWQNINgpzIxokxY1JyEdg5WphcGExuXjPDN3ChYUrkZG4h PAe7LuaGSQjyTOY/K4/O/iLODlBcM EqxCVZY8J04"=>nil}
* rack.request.form_input : #<StringIO:0x00000006f762b8>
* rack.request.form_vars : [FILTERED]
* rack.request.query_hash : {}
* rack.request.query_string :
* rack.run_once : false
* rack.session : #<ActionDispatch::Request::Session:0x00000006f6bea8>
* rack.session.options : #<ActionDispatch::Request::Session::Options:0x00000006f6be08>
* rack.url_scheme : http
* rack.version : [1, 3]
* warden : Warden::Proxy:58416640 #config={:default_scope=>:user, :scope_defaults=>{}, :default_strategies=>{:user=>[:rememberable, :database_authenticatable]}, :intercept_401=>false, :failure_app=>#<Devise::Delegator:0x00000007b40dc8>}
Thanks
Yes. It is a bot. It is trying to go through your devise's registration form. Just in case check if you have this code in your main layout: <%= csrf_meta_tags %>. It can be accidently deleted after rewriting your layout.
This is the info about IP address from which you were under attack: http://pastebin.com/c1Zb5tcP
You can try to cut spammer using your resources with rack-attack gem
There is a simple configuration to start with it, after installation.
There is also another solution, to create a rule in the INPUT chain in your IPtables, and block traffic from the IP address you provided, in case that you have access to your server:
iptables -I INPUT -s 107.15.69.216 -j DROP

Ruby on Rails "invalid byte sequence in UTF-8" due to bot

I have some errors triggered by a chinese bot: http://www.easou.com/search/spider.html when it scrolls my websites.
Versions of my applications are all with Ruby 1.9.3 and Rails 3.2.X
Here a stacktrace :
An ArgumentError occurred in listings#show:
invalid byte sequence in UTF-8
rack (1.4.5) lib/rack/utils.rb:104:in `normalize_params'
-------------------------------
Request:
-------------------------------
* URL : http://www.my-website.com
* IP address: X.X.X.X
* Parameters: {"action"=>"show", "controller"=>"listings", "id"=>"location-t7-villeurbanne--58"}
* Rails root: /.../releases/20140708150222
* Timestamp : 2014-07-09 02:57:43 +0200
-------------------------------
Backtrace:
-------------------------------
rack (1.4.5) lib/rack/utils.rb:104:in `normalize_params'
rack (1.4.5) lib/rack/utils.rb:96:in `block in parse_nested_query'
rack (1.4.5) lib/rack/utils.rb:93:in `each'
rack (1.4.5) lib/rack/utils.rb:93:in `parse_nested_query'
rack (1.4.5) lib/rack/request.rb:332:in `parse_query'
actionpack (3.2.18) lib/action_dispatch/http/request.rb:275:in `parse_query'
rack (1.4.5) lib/rack/request.rb:209:in `POST'
actionpack (3.2.18) lib/action_dispatch/http/request.rb:237:in `POST'
actionpack (3.2.18) lib/action_dispatch/http/parameters.rb:10:in `parameters'
-------------------------------
Session:
-------------------------------
* session id: nil
* data: {}
-------------------------------
Environment:
-------------------------------
* CONTENT_LENGTH : 514
* CONTENT_TYPE : application/x-www-form-urlencoded
* HTTP_ACCEPT : text/html, application/xml;q=0.9, application/xhtml+xml, image/png, image/jpeg, image/gif, image/x-xbitmap, */*;q=0.1
* HTTP_ACCEPT_ENCODING : gzip, deflate
* HTTP_ACCEPT_LANGUAGE : zh;q=0.9,en;q=0.8
* HTTP_CONNECTION : close
* HTTP_HOST : www.my-website.com
* HTTP_REFER : http://www.my-website.com/
* HTTP_USER_AGENT : Mozilla/5.0 (compatible; EasouSpider; +http://www.easou.com/search/spider.html)
* ORIGINAL_FULLPATH : /
* PASSENGER_APP_SPAWNER_IDLE_TIME : -1
* PASSENGER_APP_TYPE : rack
* PASSENGER_CONNECT_PASSWORD : [FILTERED]
* PASSENGER_DEBUGGER : false
* PASSENGER_ENVIRONMENT : production
* PASSENGER_FRAMEWORK_SPAWNER_IDLE_TIME : -1
* PASSENGER_FRIENDLY_ERROR_PAGES : true
* PASSENGER_GROUP :
* PASSENGER_MAX_REQUESTS : 0
* PASSENGER_MIN_INSTANCES : 1
* PASSENGER_SHOW_VERSION_IN_HEADER : true
* PASSENGER_SPAWN_METHOD : smart-lv2
* PASSENGER_USER :
* PASSENGER_USE_GLOBAL_QUEUE : true
* PATH_INFO : /
* QUERY_STRING :
* REMOTE_ADDR : 183.60.212.153
* REMOTE_PORT : 52997
* REQUEST_METHOD : GET
* REQUEST_URI : /
* SCGI : 1
* SCRIPT_NAME :
* SERVER_PORT : 80
* SERVER_PROTOCOL : HTTP/1.1
* SERVER_SOFTWARE : nginx/1.2.6
* UNION_STATION_SUPPORT : false
* _ : _
* action_controller.instance : listings#show
* action_dispatch.backtrace_cleaner : #<Rails::BacktraceCleaner:0x000000056e8660>
* action_dispatch.cookies : #<ActionDispatch::Cookies::CookieJar:0x00000006564e28>
* action_dispatch.logger : #<ActiveSupport::TaggedLogging:0x0000000318aff8>
* action_dispatch.parameter_filter : [:password, /RAW_POST_DATA/, /RAW_POST_DATA/, /RAW_POST_DATA/]
* action_dispatch.remote_ip : 183.60.212.153
* action_dispatch.request.content_type : application/x-www-form-urlencoded
* action_dispatch.request.parameters : {"action"=>"show", "controller"=>"listings", "id"=>"location-t7-villeurbanne--58"}
* action_dispatch.request.path_parameters : {:action=>"show", :controller=>"listings", :id=>"location-t7-villeurbanne--58"}
* action_dispatch.request.query_parameters : {}
* action_dispatch.request.request_parameters : {}
* action_dispatch.request.unsigned_session_cookie: {}
* action_dispatch.request_id : 9f8afbc8ff142f91ddbd9cabee3629f3
* action_dispatch.routes : #<ActionDispatch::Routing::RouteSet:0x0000000339f370>
* action_dispatch.show_detailed_exceptions : false
* action_dispatch.show_exceptions : true
* rack-cache.allow_reload : false
* rack-cache.allow_revalidate : false
* rack-cache.cache_key : Rack::Cache::Key
* rack-cache.default_ttl : 0
* rack-cache.entitystore : rails:/
* rack-cache.ignore_headers : ["Set-Cookie"]
* rack-cache.metastore : rails:/
* rack-cache.private_headers : ["Authorization", "Cookie"]
* rack-cache.storage : #<Rack::Cache::Storage:0x000000039c5768>
* rack-cache.use_native_ttl : false
* rack-cache.verbose : false
* rack.errors : #<IO:0x000000006592a8>
* rack.input : #<PhusionPassenger::Utils::RewindableInput:0x0000000655b3a0>
* rack.multiprocess : true
* rack.multithread : false
* rack.request.cookie_hash : {}
* rack.request.form_hash :
* rack.request.form_input : #<PhusionPassenger::Utils::RewindableInput:0x0000000655b3a0>
* rack.request.form_vars : ���W�"��陷q�B��)���
�F��P Z� 8�� & G\y�P��u�T ed �.�%�mxEAẳ\�d*�Hg� �C賳�lj��� � U 1��]pgt�P�
Ɗ ��c"� ��LX��D���HR�y��p`6�l���lN�P �l�S����`V4y��c����X2� &JO!��*p �l��-�гU��w }g�ԍk�� (� F J�� q�:�5G�Jh�pί����ࡃ] �z�h���� d }�}
* rack.request.query_hash : {}
* rack.request.query_string :
* rack.run_once : false
* rack.session : {}
* rack.session.options : {:path=>"/", :domain=>nil, :expire_after=>nil, :secure=>false, :httponly=>true, :defer=>false, :renew=>false, :coder=>#<Rack::Session::Cookie::Base64::Marshal:0x000000034d4ad8>, :id=>nil}
* rack.url_scheme : http
* rack.version : [1, 0]
As you can see there is no invalid utf-8 in the url but only in the rack.request.form_vars . I have about hundred errors per days, and all similar as this one.
So, I tried to force utf-8 in rack.request.form_vars with something like this:
class RackFormVarsSanitizer
def initialize(app)
#app = app
end
def call(env)
if env["rack.request.form_vars"]
env["rack.request.form_vars"] = env["rack.request.form_vars"].force_encoding('UTF-8')
end
#app.call(env)
end
end
And I call it in my application.rb :
config.middleware.use "RackFormVarsSanitizer"
It doesn't seem to work because I already have errors. The problem is I can't test in development mode because I don't know how to set rack.request.form_vars.
I installed utf8-cleaner gem but it fixes nothing.
Somebody have an idea to fix this? or to trigger it in development?
So you don't have to piece together the comments in my other reply, this is what I'm doing now – I've seen no errors for 24 hours, so it looks very promising:
Add rack-utf8_sanitizer to your Gemfile:
gem 'rack-utf8_sanitizer'
and run
bundle
Put this middleware in app/middleware/handle_invalid_percent_encoding.rb and rename the class HandleInvalidPercentEncoding (because ExceptionApp is a bit too general).
In the config block of config/application.rb do:
require "#{Rails.root}/app/middleware/handle_invalid_percent_encoding.rb"
# NOTE: These must be in this order relative to each other.
# HandleInvalidPercentEncoding just raises for encoding errors it doesn't cover,
# so it must run after (= be inserted before) Rack::UTF8Sanitizer.
config.middleware.insert 0, HandleInvalidPercentEncoding
config.middleware.insert 0, Rack::UTF8Sanitizer # from a gem
Deploy. Done.
(app happens to be the location for middleware in the project I'm working on, but I'd probably prefer lib. Whatever. Either should work.)
Add this line to your Gemfile, then run bundle in your terminal:
gem "handle_invalid_percent_encoding_requests"
This solution is based on Henrik's answer, turned into a Rails Engine gem.
There is an issue in the gem repo with a link to someone's possible solution – they say it works for them but they're not sure if it's a good solution.
I've yet to try it, but I think I will.

Why does Authorization.current_user return a User object on one machine, but doesn't on another in Rails 3?

I have two machines running my rails app. A linux machine and MAC OS X.
The issue I am having is that when I create a new user in my app, Devise's confirmable method works just fine on one machine, but doesn't in another.
This is the error in the Linux machine:
Started GET "/users/login" for 72.252.205.36 at Sat Jun 18 18:00:35 -0500 2011
Processing by Devise::SessionsController#new as HTML
nil
Rendered devise/shared/_links.erb (1.9ms)
Rendered devise/sessions/new.html.erb within layouts/application (10.8ms)
Completed 200 OK in 90ms (Views: 18.3ms | ActiveRecord: 1.8ms)
Started GET "/users/confirmation?confirmation_token=12O-F_JMzI-SxpIEEEAh" for 72.252.205.36 at Sat Jun 18 18:02:04 -0500 2011
Processing by Devise::ConfirmationsController#show as HTML
Parameters: {"confirmation_token"=>"12O-F_JMzI-SxpIEEEAh"}
nil
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."confirmation_token" = '12O-F_JMzI-SxpIEEEAh' LIMIT 1
Slug Load (0.2ms) SELECT "slugs".* FROM "slugs" WHERE ("slugs".sluggable_id = 3 AND "slugs".sluggable_type = 'User') ORDER BY id DESC LIMIT 1
AREL (0.2ms) UPDATE "users" SET "updated_at" = '2011-06-18 23:02:04.980588', "confirmed_at" = '2011-06-18 23:02:04.977060', "confirmation_token" = NULL WHERE "users"."id" = 3
AREL (0.3ms) UPDATE "users" SET "current_sign_in_ip" = '72.252.205.36', "last_sign_in_ip" = '72.252.205.36', "updated_at" = '2011-06-18 23:02:04.986283', "sign_in_count" = 1, "current_sign_in_at" = '2011-06-18 23:02:04.984989', "last_sign_in_at" = '2011-06-18 23:02:04.984989' WHERE "users"."id" = 3
Completed 500 Internal Server Error in 88ms
NoMethodError (undefined method `update_space' for #<Authorization::AnonymousUser:0xb611f240 #role_symbols=[:guest]>):
app/controllers/application_controller.rb:27:in `after_sign_in_path_for'
Rendered /usr/lib/ruby/gems/1.8/gems/actionpack-3.0.8/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.6ms)
Rendered /usr/lib/ruby/gems/1.8/gems/actionpack-3.0.8/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (11.6ms)
Rendered /usr/lib/ruby/gems/1.8/gems/actionpack-3.0.8/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (17.9ms)
But on OS X, this is what happens with the same action:
Started GET "/users/login" for 127.0.0.1 at 2011-06-18 18:02:49 -0500
Processing by Devise::SessionsController#new as HTML
nil
Rendered devise/shared/_links.erb (2.1ms)
Rendered devise/sessions/new.html.erb within layouts/application (38.2ms)
Completed 200 OK in 159ms (Views: 87.9ms | ActiveRecord: 269.9ms)
Started GET "/users/confirmation?confirmation_token=35eDT14LmVL5eusrsIRH" for 127.0.0.1 at 2011-06-18 18:03:12 -0500
Processing by Devise::ConfirmationsController#show as HTML
Parameters: {"confirmation_token"=>"35eDT14LmVL5eusrsIRH"}
nil
User Load (2.2ms) SELECT "users".* FROM "users" WHERE "users"."confirmation_token" = '35eDT14LmVL5eusrsIRH' LIMIT 1
Slug Load (0.5ms) SELECT "slugs".* FROM "slugs" WHERE ("slugs".sluggable_id = 29 AND "slugs".sluggable_type = 'User') ORDER BY id DESC LIMIT 1
AREL (0.4ms) UPDATE "users" SET "confirmation_token" = NULL, "confirmed_at" = '2011-06-18 23:03:12.450907', "updated_at" = '2011-06-18 23:03:12.456550' WHERE "users"."id" = 29
AREL (0.4ms) UPDATE "users" SET "last_sign_in_at" = '2011-06-18 23:03:12.461899', "current_sign_in_at" = '2011-06-18 23:03:12.461899', "last_sign_in_ip" = '127.0.0.1', "current_sign_in_ip" = '127.0.0.1', "sign_in_count" = 1, "updated_at" = '2011-06-18 23:03:12.462653' WHERE "users"."id" = 29
Redirected to http://localhost:3000/home/index
Completed 302 Found in 118ms
Here are the appropriate snippets of code.
From the Application_Controller.rb
def after_sign_in_path_for(resource)
Authorization.current_user.update_space
if resource.is_a?(User) && resource.has_trial_expired?
return url_for(:settings)
end
super
end
From the User.rb:
def update_space
total_size = 0
if self.uploads.count > 0
self.uploads.each do |upload|
total_size += upload[:image_file_size]
end
end
self.space_used = total_size
self.save
end
So I have two questions:
Why is it doing this ?
How do I fix it ?
Thanks.
Updated: I am now getting this error in production on Heroku....except this is what the error looks like:
2011-07-01T21:24:22+00:00 app[web.1]: NoMethodError (undefined method `update_space' for #<Authorization::AnonymousUser:0x7f2d783cdcd0>):
2011-07-01T21:24:22+00:00 app[web.1]: app/controllers/application_controller.rb:27:in `after_sign_in_path_for'

Resources