generating meaningful usernames in devise - ruby-on-rails

I'm trying to have my app automatically generate usernames to be used as the url. Typically they will be the users first and last name added together however when there already exists a user with the same first and last name it will append a number to the name that increases for each.
This is the method i created:
def full_name
first_name + ' ' + last_name
end
def user_name
t_user_name = first_name.downcase.strip.gsub(' ', '').gsub(/[^\w-]/, '') + last_name.downcase.strip.gsub(' ', '').gsub(/[^\w-]/, '')
user_name = t_user_name
num = 1
while User.find_by_user_name(user_name).count > 0
num += 1
user_name = "#{t_user_name}#{num}"
end
end
I'm currently getting the error:
undefined method `find_by_user_name'
Which i thought would work automatically?
I was also trying to examples shown in this post:
generate unique username (omniauth + devise)
but I kept getting the error:
Mysql2::Error: Unknown column 'users.login' in 'where clause': SELECT COUNT(*) FROM `users` WHERE `users`.`login` = 'bobweir'
Even though I added
t.string :login, null: false, default: ""
to the users table
edit2: schema.rb
ActiveRecord::Schema.define(version: 20150611033237) do
create_table "users", force: :cascade do |t|
t.string "first_name", limit: 255
t.string "last_name", limit: 255
t.string "email", limit: 255, default: "", null: false
t.string "encrypted_password", limit: 255, default: "", null: false
t.string "reset_password_token", limit: 255
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", limit: 4, default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip", limit: 255
t.string "last_sign_in_ip", limit: 255
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end

Rails achieves find_by_sth magic by inferring an attribute name in your method call, thus returning an ActiveRecordRelation.
As you have no user_name attribute in your model, Active Record will not be able to perform a search on it (just imagine it has to be translated into an SQL query).
On the other hand, I'd re-think the logic of your user_name method if I were you. Consider persisting the user_name on your database.
By the way, in the second error you mention, notice that the example you have is working with a login attribute, which you simply don't have.

Related

Rails saves value to database beyond limit restriction

I have this schema in Rails 6
create_table "fields", force: :cascade do |t|
t.string "title", limit: 100
t.text "description"
t.string "slug", limit: 20
t.integer "requests"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.index ["slug"], name: "index_fields_on_slug", unique: true
t.index ["title"], name: "index_fields_on_title", unique: true
And inside rails console:
field = Field.new
field.slug = 'a' *25
field.save
And the entry is saved succesfully inside fields table.
Why? I have a limit of 20 for :slug. Shouldn't that fail without validate in the model?

ActiveRecord::RecordInvalid: Validation failed: Users must exist

I am trying to seed an sqlite3 db from a json file as a project. I have two models user and logins.
require 'json'
records = JSON.parse(File.read('db/people.json'))
records.each do |record|
User.create!(record.except('logins').merge('password' => 'encrypted password'))
end
records.each do |record|
Login.create!(record['logins'])
end
When I run my rails db:seed it successfully seeds the users and then fails when creating the logins with this error ActiveRecord::RecordInvalid: Validation failed: Users must exist It may be something with my schema or my seed script im not sure which
ActiveRecord::Schema.define(version: 2020_03_30_164743) do
create_table "logins", force: :cascade do |t|
t.datetime "date"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.index ["user_id"], name: "index_logins_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "city"
t.string "state"
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
Here is a link to my source code https://github.com/jslack2537/apiDemoApp
it may work if you write the login inside the same loop..
records.each do |record|
u = User.new(record.except('logins').merge('password' => 'encrypted password'))
u.logins = record['logins'].map{|l| Login.new(l)}
u.save!
end

ActiveRecord is not aware of timezones?

I have one question regarding to time zone
I have done the following yet, my activerecord is not still matching with my timezone when I do following query
def stock_by_date(date)
UserStock.where("date(created_at) = ? and user_id = ? ", date , current_user.id)
end
I did the following in side my application.rb
config.active_record.default_timezone = :utc
config.active_record.time_zone_aware_attributes = true
config.beginning_of_week = :sunday
config.active_record.time_zone_aware_types = [:datetime, :time]
I added timezone field to my sign up method, and it shows the current day of timezone correctly, yet when I added a stock for the current day timezone, it shows up in either the previous day or next day of current daytime zone and when I added my stock, the timestamp is for a day before when I look at the rails console
My schema.rb
ActiveRecord::Schema.define(version: 2018_11_28_183416) do
create_table "friendships", force: :cascade do |t|
t.integer "user_id"
t.integer "friend_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["friend_id"], name: "index_friendships_on_friend_id"
t.index ["user_id"], name: "index_friendships_on_user_id"
end
create_table "notes", force: :cascade do |t|
t.string "content"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "user_id"
t.index ["user_id"], name: "index_notes_on_user_id"
end
create_table "stocks", force: :cascade do |t|
t.string "ticker"
t.string "name"
t.decimal "last_price"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "user_stocks", force: :cascade do |t|
t.integer "user_id"
t.integer "stock_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["stock_id"], name: "index_user_stocks_on_stock_id"
t.index ["user_id"], name: "index_user_stocks_on_user_id"
end
create_table "users", force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "first_name"
t.string "last_name"
t.string "time_zone", default: "UTC"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
end
end
for example,
How can I fix this issue?
Note: If more info is needed, please let me know
Note: for the matter of being concise this is my repo
Note: my configuration does not show a reliable behavior at all and I am very confused :/ and I have the same issue for note of a current day
----update-------------------
In my rails console
create a migration with this content to remove the default value to created_at, so it's not filled by default on database level.
change_column_default(:user_stocks, :created_at, nil)
after that, when you create a new UserStock, you need to specify the created_at value, and there you can specify the created_at with the date of the user, taking care of the timezone.
UserStock.create(created_at: Time.now.in_time_zone(user.time_zone).to_time...)
or you can just maybe add it to a callback on the model so it's automatic everytime you create a UserStock, it change the value
class UserStock < ActiveRecord::Base
before_create :set_created_at
private
def set_created_at
self.created_at = time.now.in_time_zone(self.user.time_zone).to_time
end
end
so everytime you create one, the value is correct. with that it may work as expected.
Another option if you don't need it just for that specific model and use them for all the user interaction, you can create a before filter on the application controller to set the time zone dinamically, something like
class ApplicationController < ActionController::Base
before_filter :set_time_zone
def set_time_zone(&block)
time_zone = current_user.try(:time_zone) || 'UTC'
Time.use_zone(time_zone, &block)
end
end
Did you try the query by specifying the range?
Because you're trying to find the user_stocks that are created on some date. But notice that created_at is a datetime object and I guess your date variable might be just a date object.
def stock_by_date(date)
UserStock.where(created_at: date.midnight..date.end_of_day, user_id: current_user.id)
end

Why am I getting "PG::NotNullViolation null value in column "id" violates not-null constraint" whenever I login in my rails app?

After dumping, downloading and pg_restoring a DB from Heroku, any time I try to login in my rails application I get the above error.
It somehow seems that the user id is seen as nil (even though I can see an id value in the DB).
I also read that it may be due to the id being a simple int instead of a serial, however, as you can see in my schema:
create_table "users", id: :serial, force: :cascade do |t|
t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "name"
t.string "last_name"
t.string "provider"
t.string "uid"
t.boolean "admin", default: false, null: false
t.boolean "affiliate_approved", default: false, null: false
t.integer "cart_id"
t.float "rev_share"
t.boolean "notice", default: false, null: false
t.string "iban"
t.string "piva"
t.string "invitation_token"
t.datetime "invitation_created_at"
t.datetime "invitation_sent_at"
t.datetime "invitation_accepted_at"
t.integer "invitation_limit"
t.string "invited_by_type"
t.integer "invited_by_id"
t.integer "invitations_count", default: 0
t.string "username"
t.string "slug"
t.integer "enrolls_count", default: 0
t.integer "partner_id"
t.string "country"
t.integer "referrer"
t.boolean "gdpr_marketing"
t.boolean "privacy_policy"
t.boolean "subscription", default: false
t.date "account_created_at"
t.boolean "profilazione"
t.boolean "terms_and_conditions"
t.index ["email"], name: "index_users_on_email", unique: true
t.index ["invitation_token"], name: "index_users_on_invitation_token", unique: true
t.index ["invitations_count"], name: "index_users_on_invitations_count"
t.index ["invited_by_id"], name: "index_users_on_invited_by_id"
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
t.index ["username"], name: "index_users_on_username", unique: true
end
And it seems that the id is used already as serial.
Do you have any idea of what may be going wrong? This application is live in production with a couple of thousands of users who aren't being impacted by this issue, which makes me think there's something wrong with my local PG setup.
Edit - full error message
PG::NotNullViolation at /auth/google_oauth2/callback
ERROR: null value in column "id" violates not-null constraint
DETAIL: Failing row contains (null, 9367, 127.0.0.1, 2018-09-17 09:51:59.463125, 2018-09-17 09:51:59.463125).
Edit - more findings
In user.rb (the model file) there's an after_update hook where the following is executed:
def change_log
UserChange.create(ip_request: current_sign_in_ip, user: self)
end
This is so that we can track everything a user changes along with their IP (GDPR reasons).
After commenting that out, it all works alright and my user gets logged in as planned
There must be a callback to another table which is trying to persist with a null ID. Check for callbacks and the schema for any related tables. In your case this was the UserChange table.
I just had the same error after pulling a copy of the DB from Heroku:
PG::NotNullViolation: ERROR: null value in column "id" violates not-null constraint DETAIL: Failing row contains ...etc
It was happening every time I tried to create a new record. I'm guessing that when you log in, your app is creating a new record somewhere (possibly some login tracking/logging you are doing?) that is triggering the error. If you can't access the app through a web browser, you could try opening up the Rails console and see what happens if you try to create a new record directly. If you still get the error, the issue is not actually with your login but with your DB.
The issue for me was that I was using a different version of Postgres on my dev machine to the version on Heroku that created the dump file. After switching to the matching version of Postgres an re-pulling the DB, everything is working as expected again.
If you're using Postgres on Mac, when you add a new Postgres server, you can choose which version of Postgres it should use. You want to make your development and production environments as similar as possible so you definitely want to make sure that your DB versions match.

Rake db:seed refuses to insert data into a particular database column

I’m having a very peculiar thing happen when I run a seed program to add users to my Rails app -- one of the columns absolutely refuses to be populated. It’s a user populate method, with some of the elements generated by the Faker gem.
The Faker items work just fine and insert into the database, except for the Faker::Avatar method. So I decided to try my own custom string with a randomly generated number for the avatar number. But nothing worked.
Here is the Users table from the schema:
create_table "users", force: :cascade do |t|
t.string "email", limit: 191, default: "", null: false
t.string "encrypted_password", limit: 191, default: "", null: false
t.string "reset_password_token", limit: 191
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
t.integer "sign_in_count", limit: 4, default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip", limit: 191
t.string "last_sign_in_ip", limit: 191
t.datetime "created_at"
t.datetime "updated_at"
t.string "first_name", limit: 45
t.string "last_name", limit: 45
t.string "username", limit: 30
t.string "location", limit: 191
t.text "profile", limit: 65535
t.string "avatar", limit: 191
end
And here is the seeding method for the User:
1.times do
user = User.create!(
first_name: Faker::Name.first_name,
last_name: Faker::Name.last_name,
username: Faker::Internet.user_name,
email: Faker::Internet.safe_email,
password: Faker::Internet.password(8, 16),
location: Faker::Address.city + ', ' + Faker::Address.state,
profile: Faker::Lorem.sentence(rand(15..60)),
avatar: 'avatar' + Random.rand(1...180).to_s + '.jpg'
I am trying to figure out why I can't insert anything into the avatar column, either from Faker or my own string. It just seems strange!
This is caused by the uploader that is mounted to your avatar field.
The easiest solution is to comment out the mount_uploader line, seed the data and then uncomment the line.
If you look at the documentation for Ruby class Random here, the rand method does not support the signature you use. This should work if you change your code to:
avatar: 'avatar' + Random.rand(180).to_s + '.jpg'

Resources