Rails 5 model objects not showing all Devise attributes - ruby-on-rails

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

Related

ActionView::Template::Error (PG::UndefinedColumn: ERROR: column posts.user_id does not exist

my code is working fine on my system in development mode but when i pushed to heroku, i am getting this error on the logs.
i'm on Rails 5.2.3 & ruby 2.3.3
ActionView::Template::Error (PG::UndefinedColumn: ERROR: column posts.user_id does not exist
LINE 1: SELECT COUNT(*) FROM "posts" WHERE "posts"."user_id" = $1
On heroku console, when i try to retrieve user_id i get
irb(main):001:0> p = Post.last
Post Load (11.0ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT $1 [["LIMIT", 1]]
=> nil
irb(main):002:0> p.user_id
Traceback (most recent call last):
1: from (irb):2
NoMethodError (undefined method `user_id' for nil:NilClass)
irb(main):003:0> ! ECONNRESET: read ECONNRESET
but on development i get
irb(main):001:0> p =Post.last
Post Load (0.3ms) SELECT "posts".* FROM "posts" ORDER BY "posts"."id" DESC LIMIT ? [["LIMIT", 1]]
=> #<Post id: 13, description: "#snopp", user_id: 1, created_at: "2019-05-02 15:38:09", updated_at: "2019-05-02 15:38:09", image_file_name: nil, image_content_type: nil, image_file_size: nil, image_updated_at: nil>
irb(main):002:0> p.user_id
=> 1
irb(main):003:0>
this is my schema.rb
ActiveRecord::Schema.define(version: 2019_05_02_123348) do
create_table "active_storage_attachments", force: :cascade do |t|
t.string "name", null: false
t.string "record_type", null: false
t.integer "record_id", null: false
t.integer "blob_id", null: false
t.datetime "created_at", null: false
t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
end
create_table "active_storage_blobs", force: :cascade do |t|
t.string "key", null: false
t.string "filename", null: false
t.string "content_type"
t.text "metadata"
t.bigint "byte_size", null: false
t.string "checksum", null: false
t.datetime "created_at", null: false
t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
end
create_table "hash_tags", force: :cascade do |t|
t.string "name"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "post_hash_tags", force: :cascade do |t|
t.integer "post_id"
t.integer "hash_tag_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["hash_tag_id"], name: "index_post_hash_tags_on_hash_tag_id"
t.index ["post_id"], name: "index_post_hash_tags_on_post_id"
end
create_table "posts", force: :cascade do |t|
t.string "description"
t.integer "user_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "image_file_name"
t.string "image_content_type"
t.bigint "image_file_size"
t.datetime "image_updated_at"
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.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"
t.string "name"
t.string "website"
t.text "bio"
t.integer "phone"
t.string "gender"
t.string "avatar"
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
Post Model
class Post < ApplicationRecord
after_commit :create_hash_tags, on: :create
has_many :post_hash_tags
has_many :hash_tags, through: :post_hash_tags
belongs_to :user
end
user model
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :trackable
has_many :posts, dependent: :destroy
end
heroku pg:reset
heroku run rake db:migrate
heroku restart
There is no instances of Post which gives you the error of NilClass. You can seed the database as suggested in the other post. For more information about seeding a database check the rails docs on seeding.
To test your application on Heroku which we would assume is running in production mode, you'll probably want to seed the production database.
You should have a db/seeds.rb file where you can do this.
See this answer for ways you can use it.
Also see Rails Docs for ideas.
If you build your seeds with seeds.rb file you should be able to run
heroku run rake db:seed
not sure if we can set automated migration while deploying to the heroku,
but once the code is deployed to the heroku you need to run
heroku run rake db:migrate
and your problem will be solved.

Seeding SQLite with Devise Model Gives Uniqueness Constraint Error

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

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.

Rails not assigning a value for "created_at" attribute or for "id."

I'm new to programming and have been learning Ruby on Rails for about 10 weeks. In the Rails console, whenever I create a new instance of one of my models, all attributes come up nil:
2.0.0-p576 :002 > List.create
(0.1ms) begin transaction
(0.1ms) rollback transaction
=> #<List id: nil, name: nil, user_id: nil, created_at: nil, updated_at: nil>
Isn't Rails supposed to generate List id and created_at automatically when I create the model instance?
Hereis my schema file:
ActiveRecord::Schema.define(version: 20141124011011) do
create_table "items", force: true do |t|
t.string "body"
t.integer "list_id"
t.boolean "done", default: false
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "items", ["list_id"], name: "index_items_on_list_id"
create_table "lists", force: true do |t|
t.string "name"
t.integer "user_id"
t.datetime "created_at"
t.datetime "updated_at"
end
add_index "lists", ["user_id"], name: "index_lists_on_user_id"
create_table "users", force: true do |t|
t.string "name"
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.string "confirmation_token"
t.datetime "confirmed_at"
t.datetime "confirmation_sent_at"
t.string "unconfirmed_email"
t.datetime "created_at"
t.datetime "updated_at"
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
end
I know this should be a simple question and I have searched for a while now for an answer, but haven't come up with anything. Any help is appreciated.
Here is the model:
class List < ActiveRecord::Base
belongs_to :user
has_many :items
validates :name, length: { minimum: 5 }, presence: true
validates :user, presence: true
end
I added values to list name and user so that it would pass validation, but I'm still having the same problem.
2.0.0-p576 :001 > list = List.create(name: "Grocery List", user: User.first)
User Load (2.6ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1
(0.1ms) begin transaction
(0.2ms) rollback transaction
=> #<List id: nil, name: "Grocery List", user_id: nil, created_at: nil, updated_at: nil>
As I said in the comments, the problem you're seeing is because your object is failing validation. The clue in the log is the rollback transaction; that usually indicates some kind of exception that prevented the object from persisting.
That explains the lack of id and created_at values. Since the object never persisted, those values were never able to be set.
In your case, you've got two validators:
validates :name, length: { minimum: 5 }, presence: true
validates :user, presence: true
As is probably clear from those lines of code, both name and user need to be populated, and name must be at least 5 characters long.
So you'll have to do something like this instead:
list = List.create(name: "list_name", user: User.first)
Note: User.first can be replaced with any user object, it is merely for demonstration purposes.

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