I am trying to find out why my update method is not working in my Rails API. It should update the bio field. I have my API hosted on Heroku and am using the Heroku logs to debug in production. I used the exists? method to make sure the user is in the db and yet when the update method is called it rollsback after doing this check. I don't understand what is the cause of this?
Here are the Heroku logs of the output
2022-04-15T02:54:34.083586+00:00 app[web.1]: I, [2022-04-15T02:54:34.083515 #4] INFO -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] Started PATCH "/users/8" for 98.248.0.125 at 2022-04-15 02:54:34 +0000
2022-04-15T02:54:34.084345+00:00 app[web.1]: I, [2022-04-15T02:54:34.084290 #4] INFO -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] Processing by UsersController#update as HTML
2022-04-15T02:54:34.084376+00:00 app[web.1]: I, [2022-04-15T02:54:34.084350 #4] INFO -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] Parameters: {"bio"=>"test", "id"=>"8", "user"=>{"bio"=>"test"}}
2022-04-15T02:54:34.087450+00:00 app[web.1]: D, [2022-04-15T02:54:34.087403 #4] DEBUG -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] User Load (1.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 8], ["LIMIT", 1]]
2022-04-15T02:54:34.089711+00:00 app[web.1]: D, [2022-04-15T02:54:34.089664 #4] DEBUG -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] User Exists? (1.2ms) SELECT 1 AS one FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 8], ["LIMIT", 1]]
2022-04-15T02:54:34.092004+00:00 app[web.1]: D, [2022-04-15T02:54:34.091963 #4] DEBUG -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] TRANSACTION (0.9ms) BEGIN
2022-04-15T02:54:34.093523+00:00 app[web.1]: D, [2022-04-15T02:54:34.093465 #4] DEBUG -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] User Exists? (1.4ms) SELECT 1 AS one FROM "users" WHERE "users"."username" = $1 AND "users"."id" != $2 LIMIT $3 [["username", "newperson"], ["id", 8], ["LIMIT", 1]]
2022-04-15T02:54:34.095530+00:00 app[web.1]: D, [2022-04-15T02:54:34.095493 #4] DEBUG -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] TRANSACTION (0.9ms) ROLLBACK
2022-04-15T02:54:34.096881+00:00 app[web.1]: I, [2022-04-15T02:54:34.096842 #4] INFO -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] [active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (0.07ms)
2022-04-15T02:54:34.097078+00:00 app[web.1]: I, [2022-04-15T02:54:34.097050 #4] INFO -- : [9e5ea776-5b15-420f-8cdc-0601480e0e3d] Completed 422 Unprocessable Entity in 13ms (Views: 0.6ms | ActiveRecord: 5.5ms | Allocations: 2816)
2022-04-15T02:54:34.101664+00:00 heroku[router]: at=info method=PATCH path="/users/8" host=anime-axis-api.herokuapp.com request_id=9e5ea776-5b15-420f-8cdc-0601480e0e3d fwd="98.248.0.125" dyno=web.1 connect=0ms service=17ms status=422 bytes=1096 protocol=https
Here is my update method:
def update
if User.exists?(8)
#current_user.update!(user_params)
render json: #current_user, status: :ok
end
end
private
def user_params
# added require
params.require(:user).permit(:username, :password, :password_confirmation, :bio, :avatar, :email)
end
My User model:
class User < ApplicationRecord
has_secure_password
has_many :anime_lists
has_many :animes, through: :anime_lists
has_many :manga_lists
has_many :mangas, through: :manga_lists
validates :username, presence: true, confirmation: {case_sensitive: false}, uniqueness: true, length: {in: 6..30}
validates :password, presence: true, confirmation: true
end
I think your validations are the issue. Password presence is validating on every update. Since User#password is nil and you don't have a password in your params, it fails.
class User < ApplicationRecord
has_secure_password
validates :password, presence: true, confirmation: true
end
>> User.create(email: 'test#user.com', password: '123456');
>> User.first.update!(email: 'test#user.com')
User Load (0.8ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1 [["LIMIT", 1]]
ActiveRecord::RecordInvalid: Validation failed: Password can't be blank
has_secure_password also adds its own validations.
https://api.rubyonrails.org/classes/ActiveModel/SecurePassword/ClassMethods.html#method-i-has_secure_password
If you want to customize password validations use
has_secure_password validations: false
# + your password validations
To get some ideas, you can take a look at how devise does validations:
https://github.com/heartcombo/devise/blob/v4.8.1/lib/devise/models/validatable.rb#L60
I can not be totally sure without knowing the data in your database but I would say you have two users with username=newperson.
When you try to save any change on any of those the validation triggers and the changes are not commited to the dabase.
Related
I'm in the process of writing a single page app with rails, react, and redux; and this is what the full error message looks like:
Started POST "/api/users" for ::1 at 2020-01-27 21:48:27 -0800
Processing by Api::UsersController#create as JSON
Parameters: {"user"=>{"username"=>"racookin", "password"=>"[FILTERED]", "nickname"=>"racookin", "gender"=>"female", "birthday"=>"1990-07-07"}}
(0.2ms) BEGIN
↳ app/controllers/api/users_controller.rb:6
User Exists (0.4ms) SELECT 1 AS one FROM "users" WHERE "users"."username" = $1 LIMIT $2 [["username", "racookin"], ["LIMIT", 1]]
↳ app/controllers/api/users_controller.rb:6
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE "users"."email" IS NULL LIMIT $1 [["LIMIT", 1]]
↳ app/controllers/api/users_controller.rb:6
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE "users"."session_token" = $1 LIMIT $2 [["session_token", "9B3Uo1FGMnJDeASGGucj_Q"], ["LIMIT", 1]]
↳ app/controllers/api/users_controller.rb:6
(0.2ms) ROLLBACK
↳ app/controllers/api/users_controller.rb:6
Completed 401 Unauthorized in 274ms (Views: 0.2ms | ActiveRecord: 10.6ms)
I'm trying to understand what this is saying so that I can figure out where to even start looking for the bug; it seems that it returns the 401 Unauthorized error, and it's saying that the user exists (even when I try signing up with a new user). What exactly is happening here? Also, is it hitting the database 3 times?
Update: I think I understand that it's failing because the user isn't being saved, which means it's probably failing one of the validations.
Here's what I have on my User model:
class User < ApplicationRecord
attr_reader :password
validates :username, :email, :nickname, :gender, :birthday, :password_digest, :session_token, presence: true
validates :username, :email, :session_token, uniqueness: true
validates :password, length: {minimum: 6}, allow_nil: true
after_initialize :ensure_session_token
...
And here's a more detailed look at my schema for the users table:
# Table name: users
#
# id :bigint not null, primary key
# username :string not null
# email :string not null
# nickname :string not null
# gender :string not null
# birthday :date not null
# password_digest :string not null
# session_token :string not null
# created_at :datetime not null
# updated_at :datetime not null
Could one of these validations be failing? I assumed that because the values for these columns are being set in the form, my user would pass the validations; but am I wrong?
UPDATE: I've fixed the email parameter issue, but I still seem to be getting the 401 status error:
Started POST "/api/users" for ::1 at 2020-01-28 08:54:20 -0800
Processing by Api::UsersController#create as JSON
Parameters: {"user"=>{"username"=>"", "password"=>"[FILTERED]", "nickname"=>"pooh", "gender"=>"male", "birthday"=>"2002-02-02", "email"=>"pooh10"}}
(0.2ms) BEGIN
↳ app/controllers/api/users_controller.rb:6
User Exists (1.3ms) SELECT 1 AS one FROM "users" WHERE "users"."username" = $1 LIMIT $2 [["username", ""], ["LIMIT", 1]]
↳ app/controllers/api/users_controller.rb:6
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = $1 LIMIT $2 [["email", "pooh10"], ["LIMIT", 1]]
↳ app/controllers/api/users_controller.rb:6
User Exists (0.3ms) SELECT 1 AS one FROM "users" WHERE "users"."session_token" = $1 LIMIT $2 [["session_token", "232kGIICEzCUSSesxgeYfg"], ["LIMIT", 1]]
↳ app/controllers/api/users_controller.rb:6
(0.2ms) ROLLBACK
↳ app/controllers/api/users_controller.rb:6
Completed 401 Unauthorized in 284ms (Views: 0.3ms | ActiveRecord: 12.3ms)
As per your request params for api/users.
Parameters: {"user"=>{"username"=>"racookin", "password"=>"[FILTERED]", "nickname"=>"racookin", "gender"=>"female", "birthday"=>"1990-07-07"}}
You are not passing email in your params. And according to your models, you added uniqueness validation for email.
validates :username, :email, :session_token, uniqueness: true
Now when active record trying to validate your record with existing records, it found a record with null email so it returned validation failed message to you.
If you want to save record with null values you need to add :allow_nil => true in your models for the email field.
Edit
to set username random in your users model.
class User < ApplicationRecord
.....
.....
.....
before_save :assign_username
def assign_username
return unless self.username.blank?
self.username = SecureRandom.alphanumeric(8)
end
I am creating a Blog app. This is working well on local, but on Hroku, when I tried to post comments, We're sorry, but something went wrong. appeared.
On local, I can posts comments on each article.
I use sqLite3 for local, and postgre for heroku.
Error log
2019-03-25T07:15:44.567261+00:00 app[web.1]: D, [2019-03-25T07:15:44.567194 #4] DEBUG -- : [ff69042f-aa16-4d59-8905-8b5beacee242] [1m[36mUser Load (0.8ms)[0m [1m[34mSELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2[0m [["id", 1], ["LIMIT", 1]]
2019-03-25T07:15:44.569317+00:00 app[web.1]: D, [2019-03-25T07:15:44.569236 #4] DEBUG -- : [ff69042f-aa16-4d59-8905-8b5beacee242] [1m[36mArticle Load (1.2ms)[0m [1m[34mSELECT "articles".* FROM "articles" WHERE (2) LIMIT $1[0m [["LIMIT", 1]]
2019-03-25T07:15:44.569537+00:00 app[web.1]: I, [2019-03-25T07:15:44.569468 #4] INFO -- : [ff69042f-aa16-4d59-8905-8b5beacee242] Completed 500 Internal Server Error in 5ms (ActiveRecord: 2.0ms)
2019-03-25T07:15:44.570193+00:00 app[web.1]: F, [2019-03-25T07:15:44.570137 #4] FATAL -- : [ff69042f-aa16-4d59-8905-8b5beacee242]
2019-03-25T07:15:44.570287+00:00 app[web.1]: F, [2019-03-25T07:15:44.570226 #4] FATAL -- : [ff69042f-aa16-4d59-8905-8b5beacee242] ActiveRecord::StatementInvalid (PG::DatatypeMismatch: ERROR: argument of WHERE must be type boolean, not type integer
2019-03-25T07:15:44.570292+00:00 app[web.1]: LINE 1: SELECT "articles".* FROM "articles" WHERE (2) LIMIT $1
2019-03-25T07:15:44.570294+00:00 app[web.1]: ^
2019-03-25T07:15:44.570296+00:00 app[web.1]: : SELECT "articles".* FROM "articles" WHERE (2) LIMIT $1):
2019-03-25T07:15:44.570339+00:00 app[web.1]: F, [2019-03-25T07:15:44.570285 #4] FATAL -- : [ff69042f-aa16-4d59-8905-8b5beacee242]
2019-03-25T07:15:44.570427+00:00 app[web.1]: F, [2019-03-25T07:15:44.570372 #4] FATAL -- : [ff69042f-aa16-4d59-8905-8b5beacee242] app/controllers/comments_controller.rb:7:in `create'
timestamp_create_comments.rb
class CreateComments < ActiveRecord::Migration[5.2]
def change
create_table :comments do |t|
t.string :commenter
t.text :body
t.references :article, foreign_key: true
t.timestamps
end
end
end
So i have this code in my mode
# == Schema Information
#
# Table name: users
#
# id :integer not null, primary key
# name :string
# surname :string
# user_id :integer
# count :integer default(0)
# was :boolean default(FALSE)
# qrcode :string
# created_at :datetime not null
# updated_at :datetime not null
#
class User < ApplicationRecord
validates :name, presence: true
validates :surname, presence: true
validates :user_id, presence: true
after_create :generate_qr
private
def generate_qr
ian = User.find(id)
ian.update_attribute(:qrcode, "https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=" + user_id.to_s)
# update_attribute(:qrcode, "https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=" + user_id.to_s)
end
end
Its work fine and generate qr code on my local host. But when i deploy on heroku i have this errors in heroku logs.
2018-06-30T14:23:37.200657+00:00 app[web.1]: I, [2018-06-30T14:23:37.200507 #4] INFO -- : [56b953ac-5a43-4b25-980d-f2bc5c53883a] Parameters: {"utf8"=>"✓", "authenticity_token"=>"mBkhE7alyyKGtS4v+tnW2Vpg6c1z0kwQfbnftqTWdSukTpre29vkqVmeuVoGR7NJzs0EoxiQv0rS+WzJ4hUSOw==", "user"=>{"name"=>"fdsfds", "surname"=>"fdsfdsfds", "user_id"=>"53454"}, "commit"=>"Create User"}
2018-06-30T14:23:37.204598+00:00 app[web.1]: D, [2018-06-30T14:23:37.204527 #4] DEBUG -- : [56b953ac-5a43-4b25-980d-f2bc5c53883a] (1.1ms) BEGIN
2018-06-30T14:23:37.207575+00:00 app[web.1]: D, [2018-06-30T14:23:37.207496 #4] DEBUG -- : [56b953ac-5a43-4b25-980d-f2bc5c53883a] User Create (1.5ms) INSERT INTO "users" ("name", "surname", "user_id", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5) RETURNING "id" [["name", "fdsfds"], ["surname", "fdsfdsfds"], ["user_id", 53454], ["created_at", "2018-06-30 14:23:37.204956"], ["updated_at", "2018-06-30 14:23:37.204956"]]
2018-06-30T14:23:37.214137+00:00 app[web.1]: D, [2018-06-30T14:23:37.214060 #4] DEBUG -- : [56b953ac-5a43-4b25-980d-f2bc5c53883a] User Load (1.3ms)
SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 7], ["LIMIT", 1]]
2018-06-30T14:23:37.215729+00:00 app[web.1]: D, [2018-06-30T14:23:37.215664 #4] DEBUG -- : [56b953ac-5a43-4b25-980d-f2bc5c53883a] (1.1ms) ROLLBACK
2018-06-30T14:23:37.224955+00:00 app[web.1]: I, [2018-06-30T14:23:37.224881 #4] INFO -- : [56b953ac-5a43-4b25-980d-f2bc5c53883a] Completed 500 Internal Server Error in 24ms (ActiveRecord: 6.1ms)
2018-06-30T14:23:37.225904+00:00 app[web.1]: F, [2018-06-30T14:23:37.225838 #4] FATAL -- : [56b953ac-5a43-4b25-980d-f2bc5c53883a]
2018-06-30T14:23:37.226043+00:00 app[web.1]: F, [2018-06-30T14:23:37.225990 #4] FATAL -- : [56b953ac-5a43-4b25-980d-f2bc5c53883a] NoMethodError (undefined method `qrcode=' for #<User:0x00000004fd1d68>):
2018-06-30T14:23:37.226091+00:00 app[web.1]: F, [2018-06-30T14:23:37.226046 #4] FATAL -- : [56b953ac-5a43-4b25-980d-f2bc5c53883a]
2018-06-30T14:23:37.226146+00:00 app[web.1]: F, [2018-06-30T14:23:37.226103 #4] FATAL -- : [56b953ac-5a43-4b25-980d-f2bc5c53883a] app/models/user.rb:25:in `generate_qr'
Someone please help. I dont know where is error. Its work fine on my localhost.
The same code is working in the local but not working in Heroku
def update
current_user.update!(user_params)
response = { message: Message.account_updated}
json_response(response)
end
private
def user_params
params.permit(:first_name, :last_name, :email, :password)
end
routes.rb
namespace :api do
namespace :v1 do
put 'user/update', to: 'users#update'
end
end
user_serializer.rb
class UserSerializer < ActiveModel::Serializer
attributes :id, :username, :first_name, :last_name, :email, :created_at, :updated_at
end
that is my and it's working on my local via Postman, that is for updating user info, but while I push to Heroku and try to update via Postman then not working, log showing like this
2018-04-30T10:15:47.665731+00:00 heroku[router]: at=info method=PUT path="/api/v1/user/update?first_name=John&last_name=Doe" host=my-host.herokuapp.com request_id=79a84b63-be87-46f8-8fad-2d151a63722f fwd="27.147.231.22" dyno=web.1 connect=0ms service=18ms status=500 bytes=283 protocol=https
2018-04-30T10:15:47.648979+00:00 app[web.1]: [79a84b63-be87-46f8-8fad-2d151a63722f] Started PUT "/api/v1/user/update?first_name=John&last_name=Doe"
for 27.147.231.22 at 2018-04-30 10:15:47 +0000
2018-04-30T10:15:47.650866+00:00 app[web.1]: [79a84b63-be87-46f8-8fad-2d151a63722f] Processing by Api::V1::UsersController#update as */*
2018-04-30T10:15:47.650987+00:00 app[web.1]: [79a84b63-be87-46f8-8fad-2d151a63722f] Parameters: {"first_name"=>"John", "last_name"=>"Doe"}
2018-04-30T10:15:47.654619+00:00 app[web.1]: [79a84b63-be87-46f8-8fad-2d151a63722f] User Load (1.3ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
2018-04-30T10:15:47.656446+00:00 app[web.1]: [79a84b63-be87-46f8-8fad-2d151a63722f] CACHE User Load (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
2018-04-30T10:15:47.658345+00:00 app[web.1]: [79a84b63-be87-46f8-8fad-2d151a63722f] (1.1ms) BEGIN
2018-04-30T10:15:47.661446+00:00 app[web.1]: [79a84b63-be87-46f8-8fad-2d151a63722f] User Exists (1.2ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER($1) AND "users"."id" != $2 LIMIT $3 [["email", "j#gmail.com"], ["id", 1], ["LIMIT", 1]]
2018-04-30T10:15:47.663630+00:00 app[web.1]: [79a84b63-be87-46f8-8fad-2d151a63722f] (1.0ms) COMMIT
2018-04-30T10:15:47.664737+00:00 app[web.1]: [79a84b63-be87-46f8-8fad-2d151a63722f] [active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (0.51ms)
2018-04-30T10:15:47.665015+00:00 app[web.1]: [79a84b63-be87-46f8-8fad-2d151a63722f] Completed 500 Internal Server Error in 14ms (Views: 1.1ms | ActiveRecord: 4.5ms)
I think that's the problem
Rendered ActiveModel::Serializer::Null with Hash (0.51ms)
But I don't understand what's going on.
Update
module Response
def json_response(object, status = :ok)
render json: object, status: status
end
end
First of all
Rendered ActiveModel::Serializer::Null with Hash (0.51ms)
That's not the issue for not updating user info, it's showing in the log because ActiveModel::Serializer serialize the columns which have null value.
I think the problem is elsewhere like you need to refactor why causes this e.g you can try to remove ! update!(user_params) try like this current_user.update(user_params) or any other.
# place this method inside NullAttributesRemover or directly inside serializer class
def serializable_hash(adapter_options = nil, options = {}, adapter_instance = self.class.serialization_adapter_instance)
hash = super
hash.each { |key, value| hash.delete(key) if value.nil? }
hash
end
it will serialize columns which have only real values.
I think it will help.
I can't seem to figure out why I am getting the error :
2017-01-03T02:57:35.239505+00:00 app[web.1]: I, [2017-01-03T02:57:35.239437 #4] INFO -- : [89b504ee-5835-4bfa-a3ff-91a3a84549f6] Parameters: {"id"=>"3"}
2017-01-03T02:57:35.243975+00:00 app[web.1]: D, [2017-01-03T02:57:35.243890 #4] DEBUG -- : [89b504ee-5835-4bfa-a3ff-91a3a84549f6] User Load (1.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 22], ["LIMIT", 1]]
2017-01-03T02:57:35.468562+00:00 app[web.1]: true
2017-01-03T02:57:35.476648+00:00 app[web.1]: D, [2017-01-03T02:57:35.476563 #4] DEBUG -- : [89b504ee-5835-4bfa-a3ff-91a3a84549f6] Blueprint Load (2.7ms) SELECT "blueprints".* FROM "blueprints" WHERE "blueprints"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
2017-01-03T02:57:35.477654+00:00 app[web.1]: I, [2017-01-03T02:57:35.477582 #4] INFO -- : [89b504ee-5835-4bfa-a3ff-91a3a84549f6] Completed 500 Internal Server Error in 238ms (ActiveRecord: 5.5ms)
2017-01-03T02:57:35.478257+00:00 app[web.1]: F, [2017-01-03T02:57:35.478177 #4] FATAL -- : [89b504ee-5835-4bfa-a3ff-91a3a84549f6]
2017-01-03T02:57:35.478313+00:00 app[web.1]: F, [2017-01-03T02:57:35.478256 #4] FATAL -- : [89b504ee-5835-4bfa-a3ff-91a3a84549f6] Gmail::Client::DeliveryError (Couldn't deliver email: undefined method `subject' for nil:NilClass):
For some reason the object #current_blueprint doesn't seem to be working inside of the gmail.deliver block. Am I missing something obvious?
Appreciate any help. Thanks!
#current_blueprint = Blueprint.find(params[:id])
mail_status = gmail.deliver! do
to "email#gmail.com"
subject #current_blueprint.subject
html_part do
content_type 'text/html; charset=UTF-8'
body #current_blueprint.body
end
end
puts mail_status
Try just current_blueprint without the # sign.
Sometime a library executes a do end with a different self and can thus not access instance variables, but it should be able to access local variables that are in scope.
Just guessing, let me know whether it works.