Seeding SQLite with Devise Model Gives Uniqueness Constraint Error - ruby-on-rails

Edit
Really Stupid Mistake:
db:reset seeds the database.
I'm trying to seed a db and create users who have posts but the users keep violating the uniqueness constraint...even if there's only one of them.
At the moment, I have no model validations.
The standard User Devise schema:
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.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 "username"
end
add_index "users", ["email"], name: "index_users_on_email", unique: true
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
db/seeds.rb
1.times do |n|
email = Faker::Internet.email
username = Faker::Name.name
password = 'password'
password_confirmation = 'password'
reset_password_token = nil
id = n
User.create!(
email: email,
username: username,
password: password,
password_confirmation: password_confirmation,
reset_password_token: reset_password_token,
id: id
)
end
I have run the following:
rails c
rake db:reset
rake db:migrate
rake db:seed
>> ActiveRecord::RecordNotUnique: SQLite3::ConstraintException: UNIQUE constraint failed: users.id: INSERT INTO "users"
I have only a single user that is generated but violates the uniqueness. The stack trace tells me it is a problem with the create method but I'm not sure how to remedy this.
I only have two possible things that need to be unique at the db level and that's the index_users_on_email and index_users_on_reset_password both of which are unique if the db has been reset and seeded with only one record.
Where am I going wrong?

Here is how I created my seed for Users, hope it helps.
1.times do
user = User.new(
name: Faker::Name.name,
email: Faker::Internet.email,
password: Faker::Lorem.characters(10)
)
user.skip_confirmation!
user.save!
end
users = User.all

Related

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

Rails - Model Testing with MiniTest and Devise gem

I'm trying to test the User Model, which I've got Devise authentication.
But I've got a failure:
Failure:
UserTest#test_should_be_valid [/home/nikki/Documents/TheHackingProject/week06/monday/the_private_club/test/models/user_test.rb:12]:
Expected false to be truthy.
This is my user_test.rb file:
require 'test_helper'
class UserTest < ActiveSupport::TestCase
def setup
#user = User.create(
first_name: 'Marge',
last_name: 'Simpson',
email: 'marge#simpson.com'
)
end
test 'should be valid' do
assert #user.valid?
end
test 'first name cant be blank' do
#user.first_name = ""
assert_not #user.valid?
end
test 'last name cant be blank' do
#user.last_name = ""
assert_not #user.valid?
end
end
And this my schema.rb file:
ActiveRecord::Schema.define(version: 2018_11_05_115404) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
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.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
Also, I don't understand how can I test the password which is encrypted?

Rails 5 model objects not showing all Devise attributes

I am using Rails 5 API with devise. I have a User model. Schema looks like this.
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.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.inet "current_sign_in_ip"
t.inet "last_sign_in_ip"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["email"], name: "index_users_on_email", unique: true, using: :btree
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
end
But the issue I am having is Rails only showing :id , :email , :created_at , :updated_at attributes as part of model. For example, in rails console
User.new
=> #<User id: nil, email: "", created_at: nil, updated_at: nil>
User.first
User Load (0.5ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT $1 [["LIMIT", 1]]
=> #<User id: 2, email: "your#email.com", created_at: "2016-09-22 03:58:04", updated_at: "2016-09-22 04:54:41">
But these attributes exist in database.This problem is mentioned earlier . Devise with rails 5 . But no answers there .Please help.
Devise restricts attributes like encrypted_password so that the critical information doesn't get exposed in API calls. So to override this, you need to override serializable_hash method.
def serializable_hash(options = nil)
super(options).merge(encrypted_password: encrypted_password)
end
This is not a Rails 5 specific feature but a Devise feature to protect your attributes.
Hope that helps!
This is probably because devise does not expose their internal attributes.
So to get all attributes you can use .attributes (documented here) which returns a hash, on which you can call to_json:
user = User.find(1)
user.attributes.to_json # => contains all fields like reset_password_token etc.
Try attributes method
User.first.attributes

generating meaningful usernames in devise

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.

Password "can't be blank" when trying to create a new user via ActiveAdmin in Rails 4

My setup - Rails 4, ActiveAdmin, Devise generated User model. The users authenticate with usernames and do not have the email attribute. I am mentioning the last, as Devise heavily relies on the email attribute, so this might have to do with the problem. My exact setup and code are described in this blog post.
In ActiveAdmin back-end, I go to Users -> New User -> fill in username, password, password confirmation -> Create User. Instead of creating a new user the New User form gets wiped out and under the Password field I get the error can't be blank. When I go to the Rails console and create a new user manually User.create(username: 'Joe', password: 'password', password_confirmation: 'password') everything works and the user is able to log in at localhost:3000/users/sign_in.
I saw this SO question. If I add to my User model:
def password_required?
new_record? ? false : super
end
I can create a new user, but all of the fields (including username, encrypted password) are blank.
UPDATE As Leger suggest, I am posting my code. As I am using the built-in contrllers of Devise and Activeadmin, I think it only makes sense to post the code of my User resource in Activeadmin and my db schema:
User resource in Activeadmin:
ActiveAdmin.register User do
# This determines which attributes of the User model will be displayed in the index page. I have left only username, but feel free to uncomment the rest of the lines or add any other of the User attributes.
index do
column :username
# column :current_sign_in_at
# column :last_sign_in_at
# column :sign_in_count
default_actions
end
# Default is :email, but we need to replace this with :username
filter :username
# This is the form for creating a new user using the Admin backend. If you have added additional attributes to the User model, you need to include them here.
form do |f|
f.inputs "User Details" do
f.input :username
f.input :password
f.input :password_confirmation
end
f.actions
end
# This is related to Rails 4 and the changes it introduced in handling strong parameters. Here we replace :email with :username.
controller do
def permitted_params
params.permit admin_user: [:username, :password, :password_confirmation]
end
end
end
schema.rb:
ctiveRecord::Schema.define(version: 20131031102826) do
create_table "active_admin_comments", force: true do |t|
t.string "namespace"
t.text "body"
t.string "resource_id", null: false
t.string "resource_type", null: false
t.integer "author_id"
t.string "author_type"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "active_admin_comments", ["author_type", "author_id"], name: "index_active_admin_comments_on_author_type_and_author_id"
add_index "active_admin_comments", ["namespace"], name: "index_active_admin_comments_on_namespace"
add_index "active_admin_comments", ["resource_type", "resource_id"], name: "index_active_admin_comments_on_resource_type_and_resource_id"
create_table "admin_users", force: true 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"
t.datetime "updated_at"
end
add_index "admin_users", ["email"], name: "index_admin_users_on_email", unique: true
add_index "admin_users", ["reset_password_token"], name: "index_admin_users_on_reset_password_token", unique: true
create_table "users", force: true do |t|
t.string "username", 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"
t.datetime "updated_at"
end
add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
add_index "users", ["username"], name: "index_users_on_username", unique: true
end
Any other code is available here.
I think the problem lies in the permitted_params method in your ActiveAdmin page handling the User model:
params.permit admin_user: [:username, :password, :password_confirmation]
If this is actually the User model, the line should read:
params.permit user: [:username, :password, :password_confirmation]
That fits the simptoms you describe–empty form after submit and everything working properly in the console.

Resources