I have a User table for my app which contains the list of all users. This table has a Boolean field named active.
I have this code to fetch the user:
existing_user = User.where("LOWER(email) = ?", auth_hash['info']['email'].downcase)
And this is what I get when I do an existing_user.inspect:
User Load (1.9ms) SELECT "users".* FROM "users" WHERE (LOWER(email) = 'biswanath.chandramouli#gmail.com')
#<ActiveRecord::Relation [#<User id: 4, name: "Biswanath Chandramouli", email: "Biswanath.Chandramouli#gmail.com", last_updated_by: "", admin: true, active: true, last_updated_on: nil, created_at: "2018-10-30 08:14:59", updated_at: "2018-10-30 08:14:59"
As you can see, existing_user has the property active available as shown above.
But this code fails:
if(!existing_user.active?)
The above call throws this error:
undefined method `active?' for #<User::ActiveRecord_Relation:0x00007f0a58b2c500> Did you mean? acts_like?
When existing_user.inspect shows active: true, why does the above call existing_user.active fail? Pls help!
I think you should use if(!existing_user.first.active?). This will work in your case. Where clause returns you an array, not an object. In your case, existing_user is an array not an object.
This answer is off-topic but could save you a lot:
Every time you call this existing_user = User.where("LOWER(email) = ?", auth_hash['info']['email'].downcase), it's going to downcase all the emails in the table and look for the correct one.
I would suggest to downcase the email before saving the user and add an index on it;
before_save { self.email = self.email.downcase }
and then get the user:
user = User.where(email: auth_hash['info']['email'].downcase).first
Try this method and you'll see a big difference in the data retrieval (which is now 1.9ms)
Related
Environment - Rails 4.2, Ruby 2.3
Trying to play with scopes and created one that will return true or false for the user.superuser of the current_user, from inside the non-User Model/Controller. I am getting the expected output when current_user.superuser = true but false just goes out left field.
Breakdown:
appliance.rb (model)
scope :superuser, ->(user) { user.superuser ? true : false }
appliance_controller.rb
def list
#appliances = Appliance.all.order(:idtag)
#users = User.all
end
list.html.haml
%h5
= "Is the user a superuser? #{Appliance.superuser(current_user).to_s}"
Rails console for when querying a user that has the superuser attribute set to true
irb(main):006:0* current_user = User.first User Load ... #<User id: 3, superuser: true>
irb(main):007:0> Appliance.superuser(current_user)
=> true
Rails console for when querying a user that has the superuser attribute set to false
irb(main):008:0> current_user = User.last User Load # User id: 6, superuser: false>
irb(main):010:0* Appliance.superuser(current_user)
Appliance Load (4.1ms) SELECT "appliances".* FROM "appliances"
=>#ActiveRecord::Relation [#Appliance id:1, ... updated_at: "...">, #Appliance id:2, ... updated_at: "...">]>
Basically it's dumping Appliance.all and returns an ActiveRecord_relation instead of false. Can anyone explain why this is happening?
As per the rails api :
Scope Adds a class method for retrieving and querying objects. The method is intended to return an ActiveRecord::Relation object, which is composable with other scopes. If it returns nil or false, an all scope is returned instead.
So this is not unexpected, rather a exact expected behavior. your scope returns false, it applies all scope and dumps all of the Appliance records, which are activerecord relation objects, as stated in api.
I am using the railstutorial.org book.
I tried updating the user attributes as written in Chapter 7 of the book, but the email became nil. I have tried updating to no avail. This produces a NoMethodError in UsersController#show: undefined method `downcase' for nil:NilClass.
Here is the show.html.erb
<% provide(:title, #user.name) %>
<h1>
<%= gravatar_for #user %>
<%= #user.name %>
</h1>
Users helper
module UsersHelper
# Returns the Gravatar of the given user.
def gravatar_for(user)
gravatar_id = Digest::MD5::hexdigest(user.email.downcase)
gravatar_url = "https://secure.gravatar.com/avatar/#{gravatar_id}"
image_tag(gravatar_url, alt: user.name, class: "gravatar")
end
end
User Controller
class UsersController < ApplicationController
def new
end
def show
#user = User.find(params[:id])
end
end
User model
class User < ActiveRecord::Base
before_save { email.downcase! }
validates :name, presence: true, length: { maximum: 50 }
VALID_EMAIL_REGEX = /\A[\w+\-.]+#[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
validates :email, presence: true,
format: { with: VALID_EMAIL_REGEX },
uniqueness: { case_sensitive: false }
has_secure_password
validates :password, presence: true, length: { minimum: 6 }
end
Please I need help to fix this. Thanks.
I'm also following this tutorial, so I don't pretend to be a Rails expert.
That said, I just went back and reviewed the tutorial material surrounding the first introduction of the
before_save { email.downcase! }
syntax, and I see this at the end of Chapter 6 (listing 6.42).
I'm pretty sure this isn't working for you because your UsersController is missing a definition of the "New" method:
def new
#user = User.new
end
I'm wiling to bet that your #user object is Nil because you haven't create an instance of it yet. BTW, at this point in the tutorial, you should have also defined a Create method in UsersController.
EDIT: If your problems are limited to what is happening in the Rails console, I agree with the comments that you need to provide a complete transcript of your console session in order for folks to provide a complete answer.
Here's an example Rails console session from within my Rails Tutorial project:
Invoke the console and make it aware of my User model:
$rails console
Loading development environment (Rails 4.2.2)
require './app/models/user'
=> true
Create a User instance named "spong"
**spong = User.new**
=> <User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil, remember_digest: nil, admin: nil, activation_digest: nil, activated: false, activated_at: nil>
(Note: My User model has more attributes because I am toward the end of the Tutorial.)
Populate values for name and e-mail:
spong.name = "Yo Dawg!"
=> "Yo Dawg!"
spong.email = "YoDaWG#dawg.COM"
=> "YoDaWG#dawg.COM"
Note that my initial e-mail address is mixed case.
Invoke the downcase method:
spong.email.downcase
=> "yodawg#dawg.com"
This is working for me in the console. Now let's try the update_attributes method:
spong.update_attributes(name: "The Dude", email: "dude#AbideS.org")
This is straight out of the tutorial, but it doesn't work for me, because at this point in my journey, I have implemented features that prevent this kind of update:
(6.5ms) begin transaction
User Exists (0.5ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('dude#AbideS.org') LIMIT 1
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE LOWER("users"."email") = LOWER('dude#AbideS.org') LIMIT 1
(0.1ms) rollback transaction
=> false
As Hartl says:
Note that if any of the validations fail, such as when a password is required to save a record (as implemented in Section 6.3), the call to update_attributes will fail.
So let me try the singular version of this command:
spong.update_attribute( :email, "dude#AbideS.org")
(3.7ms) begin transaction
SQL (4.0ms) INSERT INTO "users" ("name", "email", "created_at", "updated_at", "activation_digest") VALUES (?, ?, ?, ?, ?) [["name", "The Dude"], ["email", "dude#abides.org"], ... ]
(1.2ms) commit transaction
==> true
spong.email
=> "dude#abides.org"
Not that the e-mail address is already converted to lower case in the INSERT command--exactly as expected, thanks to that
before_save { email.downcase! }
we have in our User model.
But what's with all the DB activity? This is because update_attributes updates a single attribute and saves the record without going through the normal validation procedure (which is why I am able to do this). While research this, I found this excellent discussion about update_attribute and update_attributes. Great stuff!
OK, so what happens if we try to call update_attribute when the (existing) e-mail address is blank? Let's see:
newUser = User.new
=> #<User id: nil, name: nil, email: nil, created_at: nil, updated_at: nil, password_digest: nil, remember_digest: nil, admin: nil, activation_digest: nil, activated: false, activated_at: nil>
Everything in newUser is nil. Let's try to update the e-mail address:
newUser.update_attribute(:email, "cOnFuSed#MixecCase.com")**
(1.2ms) begin transaction
SQL (3.9ms) INSERT INTO "users" ("email", "created_at", "updated_at", "activation_digest") VALUES (?, ?, ?, ?) [["email", "confused#mixeccase.com"], ...]
(0.9ms) commit transaction
=> true
Again, because of the behavior of update_attribute/update_attributes, my database is updated; somewhat counterintuitively, a record is inserted during this "update" process, but this is because I had not yet saved this (or the first) record to the DB.
I hope all this helps. At a minimum, I have demonstrated that this DOES work via the console--even with previously 'nil' values (and I learned a ton while doing the research to attempt an answer).
I am relatively new with ruby on rails. I made a relationship called friendships, which has the following attributes:
user_id, friend_id, state
Inside my friendship.rb model file, i have created an opposite method to help me get inverse friendships:
class Friendship < ActiveRecord::Base
def opposite
user = self.user_id;
friend=self.friend_id;
return Friendship.where(user_id:friend,friend_id:user);
end
end
Inside my view file i have:
<h1> Requests Ive sent: </h1>
<%#sent_friendships.each do |x|%>
<%=x.opposite%><br>
<%=x.opposite.inspect%>
<%end%>
Note: #sent_friendships is defined in my controller as: #sent_friendships=current_user.friendships.where(state:'pending');
View Output:
x.opposite:
#<Friendship::ActiveRecord_Relation:0x007fd8abcf3498>
x.opposite.inspect:
#<ActiveRecord::Relation [#<Friendship id: 4, user_id: 3, friend_id: 1, created_at: "2015-07-01 21:42:21", updated_at: "2015-07-01 21:42:21", state: "requested">]>
But after calling x.opposite.inspect, how can i access specific attributes, for example just the state? If i try x.opposite.state i get the error:
undefined method `state' for #<Friendship::ActiveRecord_Relation:0x007fd8a3f612f0>
I am confused? It clear that .state is an attribute after calling the inspect method? Help please?!
What you are returning from opposite using Active Record 'where' is an ActiveRecord::Relation which is an array like structure. So x.opposite.first.state should get what you want.
Suppose there are users records in the database. And we decided to add validation in model. Model:
class User < ActiveRecord::Base
validates_format_of :name, with: /\A[^\d]*\z/, allow_blank: true
before_validation :delete_digits_from_name
def delete_digits_from_name
self.name = name.gsub!(/\d/, '')
end
end
Scenario 1 in console:
User.create(name: 'Username 15')
User.last
=> #<User id: 14154, name: "Username"
And it's ok. But there are old record (created before adding validation) and.. scenario 2:
user = User.first
=> #<User id: 1, name: "Username 15"
user.save
=> true
user
=> #<User id: 1, name: "Username"
user.reload
=> #<User id: 1, name: "Username 15"
But why?? Why changes not saved?
The gsub! in delete_digits_from_name changes the name in place, so Rails thinks name is the same thing it loaded from the DB. It's the same object, even though you've changed its value. Rails does this to optimize away DB updates when no data has changed, and in-place editing confuses it.
Switching to self.name = self.name.gsub(/\d/, '') (no !) assigns a new String that Rails will recognize as dirty and needing saving.
You can also add name_will_change! after your gsub! to tell Rails the attribute needs saving.
There is User model, and when user creates account, letter with link for confirmation is sent to his email adress. after_callback sets user's confirmed column to false.
(I don't sure about if more than one callbacks of one type is possible, there are two after callbacks)
User.rb:
after_create :confirmation
after_create :add_user_profile
...
def confirmation
if self.guest
self.confirmed=true
elsif self.authentication
self.confirmed=true
else
self.confirmed=false
begin
confirmation_token = SecureRandom.urlsafe_base64
end while User.exists?(:confirmation_token => confirmation_token)
self.confirmation_token=confirmation_token
self.confirmation_link_sent_at=Time.now.utc
UserMailer.send_confirmation_link(self).deliver
User.delay.delete_unconfirmed(self)
end
end
But when I output last user from console:
>> User.last
User Load (1.0ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT 1
#<User id: 21, email: "somddething#mail.com", password_digest: "$2a$10$LMtsumUaS5MaiRhz3.mZ2em7Fbt3.66pbpe4863zj3b0...", created_at: "2013-05-22 17:17:18", updated_at: "2013-05-22 17:17:18", guest: false, auth_token: "lbIJftEqgwyXYymjEVdhCQ", password_reset_token: nil, password_link_sent_at: nil, confirmed: nil, confirmation_token: nil, confirmation_link_sent_at: nil>
As you can see, confirmed is nil, also others related columns too. Why?
That's not working because your are setting the confirmed attribute to the users but you are not saving it again.
Depending on your needs, you can change the callback to before_create or save the user:
def confirmation
...
self.save
end
Hop this helps!