I was setting up Devise & Omniauth as per railscasts like I usually do, only now I'm using Rails 5.0.1 and ruby 2.3.3
When I go to add a user, not even using Omniauth, just using a basic email + password + confirmation the page reloads with an error of "Email can't be blank". I can see the parameters include the email.
I used Pry to investigate - things get weird here.
[1] pry(#<RegistrationsController>)> params
=> <ActionController::Parameters {"utf8"=>"✓", "authenticity_token"=>"[removed this!]", "user"=><ActionController::Parameters {"email"=>"test#test.com", "password"=>"testtest", "password_confirmation"=>"testtest"} permitted: false>, "commit"=>"Sign up", "controller"=>"registrations", "action"=>"create"} permitted: false>
[3] pry(#<RegistrationsController>)> #user
=> #<User id: nil, email: "test#test.com", created_at: nil, updated_at: nil, first_name: nil, last_name: nil, image_url: nil, headline: nil, dob: nil, gender: nil, webpage_url: nil, twitter: nil, linkedin: nil, blog_url: nil, description: nil, country: nil, state: nil, city: nil, phone: nil, full_bio: nil, profile_claimed: nil>
[4] pry(#<RegistrationsController>)> #user.class
=> User(id: integer, email: string, encrypted_password: string, reset_password_token: string, reset_password_sent_at: datetime, remember_created_at: datetime, sign_in_count: integer, current_sign_in_at: datetime, last_sign_in_at: datetime, current_sign_in_ip: string, last_sign_in_ip: string, created_at: datetime, updated_at: datetime, first_name: string, last_name: string, image_url: string, headline: string, dob: date, gender: string, webpage_url: string, twitter: string, linkedin: string, blog_url: string, description: text, country: string, state: string, city: string, phone: string, full_bio: text, type: string, profile_claimed: boolean)
[5] pry(#<RegistrationsController>)> #user.email
=> nil
[7] pry(#<RegistrationsController>)> #user.errors
=> #<ActiveModel::Errors:0x007f9de2c82da0
#base=
#<User id: nil, email: "test#test.com", created_at: nil, updated_at: nil, first_name: nil, last_name: nil, image_url: nil, headline: nil, dob: nil, gender: nil, webpage_url: nil, twitter: nil, linkedin: nil, blog_url: nil, description: nil, country: nil, state: nil, city: nil, phone: nil, full_bio: nil, profile_claimed: nil>,
#details={:email=>[{:error=>:blank}, {:error=>:blank}]},
#messages={:email=>["can't be blank"], :password=>[], :password_confirmation=>[]}>
[8] pry(#<RegistrationsController>)> #user.email.class
=> NilClass
You can see that if I access #user it returns the hash containing the email. However if I try #user.email I get nil. And when I ask for #user.errors the message says email can't be blank.
I've been hunting a while on this one. Thanks in advance for any help!
--
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:email])
end
end
Puma server.
Started POST "/users" for ::1 at 2017-01-07 20:42:57 -0500
Processing by RegistrationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"tfBeZtXEFdZV9Rx3dJgCQJ+9hHuvgFcbc3dD9D7Q6yKki4GmlVw17/qlDm2squ3hKngX3Juu12iaM1Dki9qXig==", "user"=>{"email"=>"test#test.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Sign up"}
(0.1ms) begin transaction
(0.1ms) rollback transaction
Rendering registrations/new.html.erb within layouts/application
Rendered devise/shared/_links.html.erb (0.7ms)
Rendered registrations/new.html.erb within layouts/application (4.6ms)
--
rails console
Running via Spring preloader in process 12578
Loading development environment (Rails 5.0.1)
2.3.3 :001 > u = User.new
=> #<User id: nil, email: "", created_at: nil, updated_at: nil, first_name: nil, last_name: nil, image_url: nil, headline: nil, dob: nil, gender: nil, webpage_url: nil, twitter: nil, linkedin: nil, blog_url: nil, description: nil, country: nil, state: nil, city: nil, phone: nil, full_bio: nil, profile_claimed: nil>
2.3.3 :002 > u.email = "test#test.com"
=> "test#test.com"
2.3.3 :003 > u.password = "password"
=> "password"
2.3.3 :004 > u.password_confirmation = "password"
=> "password"
2.3.3 :005 > u.save
(0.2ms) begin transaction
(0.1ms) rollback transaction
=> false
2.3.3 :006 > u.errors
=> #<ActiveModel::Errors:0x007f87163eeac8 #base=#<User id: nil, email: "test#test.com", created_at: nil, updated_at: nil, first_name: nil, last_name: nil, image_url: nil, headline: nil, dob: nil, gender: nil, webpage_url: nil, twitter: nil, linkedin: nil, blog_url: nil, description: nil, country: nil, state: nil, city: nil, phone: nil, full_bio: nil, profile_claimed: nil>, #messages={:email=>["can't be blank"]}, #details={:email=>[{:error=>:blank}, {:error=>:blank}]}>
I believe permitted: false says that your parameters are not permitted and can't be saved. Did you set up strong parameters for Users controller?
Related
I've been getting intermittent errors while seeding with rails. I'm hoping someone can help provide some insight into the different types of the User class.
The error in full:
ActiveRecord::AssociationTypeMismatch: User(#35560) expected, got #<User id: "bedc7c4e-cdd2-4ea1-a7ee-4e6642467fba", email: "phil#email.domain", jti: "7376cf41-7f88-407d-8365-1e311d946b88", ios_device_token: nil, fcm_device_token: nil, first_name: "Phil", last_name: "6", phone_number: nil, date_of_birth: nil, super_user: true, created_at: "2023-02-08 08:16:37.559974000 +0000", updated_at: "2023-02-08 08:16:37.559974000 +0000"> which is an instance of User(#22700)
The code which causes it:
user = User.new(
first_name: 'Phil',
last_name: '6',
email: 'phil#email.domain',
super_user: true,
password: 'test1234'
)
user.skip_confirmation!
user.save!
organisation = Organisation.find_by_name('Team')
Membership.create!(
user:,
organisation:,
verified: true,
verified_at: now,
organisation_admin: true,
shift_admin: true,
email: 'phil.6#group.com',
email_confirmed: true,
category: organisation.categories.find_by_name('Developer')
)
organisation = Organisation.find_by_name('Test Org')
membership = Membership.create!(
user:,
organisation:,
verified: true,
verified_at: now,
email: 'phil#testorg.com',
email_confirmed: true
)
If I pause execution before the error I can see that user == User.first is false despite User.first and user being these two lines, which are visually identical:
#<User id: "6ce62b08-cf4c-4bfa-878a-02a1ed889c69", email: "phil#email.domain", jti: "710948b6-5f4f-40ea-ab9f-df8e3b1219c3", ios_device_token: nil, fcm_device_token: nil, first_name: "Phil", last_name: "6", phone_number: nil, date_of_birth: nil, super_user: true, created_at: "2023-02-08 08:17:06.024800000 +0000", updated_at: "2023-02-08 08:17:06.024800000 +0000">
#<User id: "6ce62b08-cf4c-4bfa-878a-02a1ed889c69", email: "phil#email.domain", jti: "710948b6-5f4f-40ea-ab9f-df8e3b1219c3", ios_device_token: nil, fcm_device_token: nil, first_name: "Phil", last_name: "6", phone_number: nil, date_of_birth: nil, super_user: true, created_at: "2023-02-08 08:17:06.024800000 +0000", updated_at: "2023-02-08 08:17:06.024800000 +0000">
It's the same thing if I compare user.class and User.first.class, they look the same but a comparison evaluates to false.
Am I doing something to mutate the local variable?
What you should be doing here is to create an assocation:
class User < ApplicationRecord
has_many :memberships
end
Then you create the memberships through that assocation instead:
user = User.create!(
first_name: 'Phil',
last_name: '6',
email: 'phil#email.domain',
super_user: true,
password: 'test1234',
confirmed_at: Time.current # the easy way to skip Devise::Confirmable
)
# make sure you use the bang method so that you're not just getting a nil
organisation = Organisation.find_by_name!('Test Org')
user.memberships.create!(
organisation: organisation,
verified: true,
verified_at: now,
organisation_admin: true,
shift_admin: true,
email: 'phil.6#group.com',
email_confirmed: true,
category: organisation.categories.find_by_name!('Developer')
)
Scenario: Show email in landing page when you click on password reset link
Given I am a user and I clicked on the password reset link inside my email
Then I am redirected to 'Change Password' page
And I see two password fields
Expected I also see the email of the user whose password is to be reset
Problem: How to get the email from only the :reset_password_token value?
Output from console when I binding.pry in the view /views/devise/passwords/edit.html.erb
[1] pry(#<#<Class:0x007fd4ec6f65f8>>)> resource
=> #<User id: nil, email: "", encrypted_password: "", reset_password_token: "Ba-9txxmmUMkU_xywypz", reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: nil, updated_at: nil, first_name: nil, last_name: nil, customer_admin_id: nil, admin_id: nil, confirmation_token: nil, confirmed_at: nil, confirmation_sent_at: nil, organization_id: nil, status: nil, middle_name: nil, type: nil, cell_number: nil, phone_number: nil, extension: nil>
also When I invoke User.find(5) I see
#<User id: 5, email: "recruiter_one+org_one#mysite.com", encrypted_password: "$2a$10$v7gYTdfoIZ9yCVIx3Xb5lOYVPly71NHtOc1mbWuHxZvt...", reset_password_token: "095a18fc2455c39e4838c322e3124d0052cf2cc0e86b7fe3486...", reset_password_sent_at: "2015-06-29 10:01:56", remember_created_at: nil, sign_in_count: 10, current_sign_in_at: "2015-06-29 10:01:04", last_sign_in_at: "2015-06-29 09:35:56", current_sign_in_ip: "192.164.79.122", last_sign_in_ip: "192.164.79.122", created_at: "2015-06-12 05:06:50", updated_at: "2015-06-29 10:01:56", first_name: "Rec One Loc One", last_name: "Peter", customer_admin_id: nil, admin_id: nil, confirmation_token: nil, confirmed_at: "2015-06-12 05:13:49", confirmation_sent_at: "2015-06-12 05:06:50", organization_id: 3, status: "active", middle_name: "", type: nil, cell_number: "", phone_number: "1231232131", extension: "">
That is:
[4] pry(#<#<Class:0x007fd4ec6f65f8>>)> User.find(5).reset_password_token
CACHE (0.0ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 5 LIMIT 1 [["id", 5]]
=> "095a18fc2455c39e4838c322e3124d0052cf2cc0e86b7fe3486f72a67c5a5315"
[5] pry(#<#<Class:0x007fd4ec6f65f8>>)>
095a18fc2455c39e4838c322e3124d0052cf2cc0e86b7fe3486f72a67c5a5315 from database does not match with Ba-9txxmmUMkU_xywypz I get from resource
PS: I use devise (3.2.4)
You should get digest from password_reset_token by
digiest = Devise.token_generator.digest(self, :reset_password_token, original_token)
where original_token is Ba-9txxmmUMkU_xywypz
Next, You can find resource by
user = User.find_by_reset_password_token(digiest)
Also, You should override password_controller#edit, and define #email variable
class PasswordsController < Devise::PasswordsController
# GET /resource/password/edit?reset_password_token=abcdef
def edit
digiest = Devise.token_generator.digest(resource_class, :reset_password_token, params[:reset_password_token])
#email = resource_class.find_by_reset_password_token(digiest).email
self.resource = resource_class.new
set_minimum_password_length
resource.reset_password_token = params[:reset_password_token]
end
end
in routes.rb
devise_for :users,
:controllers => {
:passwords => 'passwords'
}
For the latest version of devise (>= v3.3.0), you could simply use the method given by devise with_reset_password_token(:token)
User.with_reset_password_token('sxZo2fk8hux6hKyufpCx')
This will return the user if exists or returns nil.
You also would want to override the edit method of Devise::PasswordsController, or for the simplest use, keep the above code in a helper.
I would like to edit a supplier name in my heroku database. I'm having trouble accessing the name attribute:
irb(main):015:0> Supplier.where(:name => "Test")
=> #<ActiveRecord::Relation [#<Supplier id: 3070, name: "Test", email: "test#me.com", phone: "555555", website: "http://www.test.co.uk", region_id: 3, category_id: 8, created_at: "2015-02-20 13:28:59", updated_at: "2015-02-20 13:28:59", rating: 0.0, address: nil, facebook_url: nil, twitter_url: nil, google_url: nil, video_url: nil, slug: "test", logo_url: nil, image_one_url: nil, image_two_url: nil, image_three_url: nil, image_four_url: nil, description: nil, reviews_count: 0, source: nil, source_other: nil>]>
irb(main):016:0> _.name
=> "Supplier"
I'm not clear why _.name is resulting in "Supplier" rather than "Test".
Can anyone tell me what I'm missing?
Supplier.where(:name => "Test") returns multiple records. Use
supplier = Supplier.where(:name => "Test").first
supplier.name
Not sure why this is happening:
2.0.0p247 :001 > User.column_names
=> ["id", "user_name", "email", "password_digest", "created_at", "updated_at", "register_key", "culminated", "remember_token", "register_token_created_at", "profile_image", "licence_image", "first_name", "last_name", "nearest_town"]
2.0.0p247 :002 > user1 = User.create(user_name: 'james', email: 'james#killbots.com', first_name:'jj', last_name:'jj', nearest_town:'mordor')
=> #<User id: nil, user_name: "james", email: "james#killbots.com", password_digest: nil, created_at: nil, updated_at: nil, register_key: nil, culminated: nil, remember_token: nil, register_token_created_at: nil, profile_image: nil, licence_image: nil, first_name: "jj", last_name: "jj", nearest_town: "mordor">
2.0.0p247 :003 > user1.update(user_name: 'killo')
=> false
Rather than a solution, how would you go about debugging this problem from the console?
Your User record is not saved, probably because of failed validation.
You should check its validity with:
user1.valid?
and show errors:
user1.errors.full_messages
If you notice:
2.0.0p247 :002 > user1 = User.create(user_name: 'james', email: 'james#killbots.com', first_name:'jj', last_name:'jj', nearest_town:'mordor')
=> #<User id: nil, user_name: "james", email: "james#killbots.com", password_digest: nil, created_at: nil, updated_at: nil, register_key: nil, culminated: nil, remember_token: nil, register_token_created_at: nil, profile_image: nil, licence_image: nil, first_name: "jj", last_name: "jj", nearest_town: "mordor">
User record (user1) was not created at all. User id is nil. You must be having some failed validations. If the record would have been successfully created in the database then your user id would never be nil as its the primary key.
Try with User.create! instead so you know that why the record was not created, you will get the exact exception raised. For example:
2.0.0p247 :002 > user1 = User.create!(user_name: 'james', email: 'james#killbots.com', first_name:'jj', last_name:'jj',
nearest_town:'mordor')
Seems like your object is not valid. As Kirti pointed out it has not been persisted to the database as no primary key id has been returned. Checking the validity of your object would give you more information on what is up with your object. Checkout rails guides for a breakdown of validation.
I've used the execute around design pattern that is articulated in the book Eloquent Ruby to log validation errors in my rails application.
I'm capturing the errors using:
#o.errors.full_messages #{:first_name=>["can't be blank"]}
and then persisting them to a logs table, but I'd also like to capture the actual method/code that caused the error. For example:
User.create(:last_name => "Doe")
How would capture the method that caused the errors so I can log it to my validation log table.
not really sure if this is what you need, for rails 3.2:
irb(main):008:0> user = User.create()
then getting errors from it:
irb(main):009:0> user.errors
=> #<ActiveModel::Errors:0xaa84c60 #base=#<User id: nil, email: "", encrypted_password: "", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: nil, updated_at: nil, first_name: nil, last_name: nil, role: "user", approved: false>, #messages={:email=>["can't be blank"], :password=>["can't be blank"]}>
they are at the end of the response.
And also you can call errors on create action without saving the user into a variable:
irb(main):010:0> User.create().errors
(0.3ms) BEGIN
(0.1ms) ROLLBACK
=> #<ActiveModel::Errors:0xa390d78 #base=#<User id: nil, email: "", encrypted_password: "", reset_password_token: nil, reset_password_sent_at: nil, remember_created_at: nil, sign_in_count: 0, current_sign_in_at: nil, last_sign_in_at: nil, current_sign_in_ip: nil, last_sign_in_ip: nil, created_at: nil, updated_at: nil, first_name: nil, last_name: nil, role: "user", approved: false>, #messages={:email=>["can't be blank"], :password=>["can't be blank"]}>
at the end you get the same hash with errors:
#messages={:email=>["can't be blank"], :password=>["can't be blank"]}