Why "if statement" doesn't work at seeds.rb on Rails? - ruby-on-rails

I'm creating a Rails 6.0.2.2 App.
My problem is that if statement in seeds.rb file not works.
Just for curiosity, I added the if statement below.
if Plan.count == 0 # always true -- though it already have a lot of plan data.
Plan.create!(name: 'スタート')
Plan.create!(name: 'ライト')
Plan.create!(name: 'スタンダード')
end
However, every time I execute rake db:seed, it always seeds those data.
When I run rails console, it returns something like...
irb(main):073:0> Plan.count
(0.8ms) SELECT COUNT(*) FROM "plans"
=> 3
irb(main):074:0> Plan.count
(1.0ms) SELECT COUNT(*) FROM "plans"
=> 6
irb(main):076:0> Plan.count
(1.3ms) SELECT COUNT(*) FROM "plans"
=> 9
irb(main):077:0> Plan.count
(1.5ms) SELECT COUNT(*) FROM "plans"
=> 12
Why Plan.all.count returns 0 wrongly?

Very strange. Create an array of plant names, iterate and create like below
["Plant 1", "Plant 2", "Plant 3"].each do |plant|
Plant.find_or_create_by!(name: plant)
end

Related

Caching with instance variable is degrading performance

All examples below would have called both pending_notifications? and reviewable_notifications
I have the following set of instance methods for User:
def pending_notifications?
return true if reviewable_notifications.size > 0
end
def reviewable_notifications
#reviewable_notifications ||= self.employee.notifications.where(read: [nil, false])
end
They are used by the view in the following manner:
<% if current_user.pending_notifications? %>
<li><%= link_to fa_icon("envelope") + " #{current_user.reviewable_notifications.count} Notification(s)", user_notifications_path(id: current_user.id) %></li>
<% else %>
<li><%= link_to fa_icon("inbox") + " Notification Center", user_notifications_path(id: current_user.id) %></li>
<% end %>
When I analyze the load, one query is being called:
SELECT COUNT(*) FROM "notifications" WHERE "notifications"."employee_id" = ? AND (("notifications"."read" = 'f' OR "notifications"."read" IS NULL))
This is fine, but before my refactor, I was not using the recommended technique of caching with an instance variable, but I got the exact same query in my analysis. Furthermore, it was consistently running at about 20ms less. Below is how the code was originally written. Why wasn't Rails calling the same query twice? Why is the performance better with the code written this way?
def pending_notifications?
return true if self.employee.notifications.where(read: [nil, false]).size > 0
end
def reviewable_notifications
self.employee.notifications.where(read: [nil, false])
end
Memoizing a value like this is only useful if there's an expensive calculation made in Ruby and you use that value in multiple places.
This particular calculation happens in SQL and Rails already caches DB queries by default, so that's why you didn't see any change.
The difference is not based on the query that is being generated...
It is that if you use
`#reviewable_notifications ||= self.employee.notifications.where(read: [nil, false])`
you will only hit the database as long as #reviewable_notifications is nil.
In the moment it takes a value, it will be used.
As an easy example you can write this in the console:
2.1.2 :001 > 5.times { User.first } # no caching, hit 5 times your DB
User Load (0.2ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
=> 5
2.1.2 :002 > 5.times { #user ||= User.first } # caching, only 1 hit
User Load (0.1ms) SELECT `users`.* FROM `users` ORDER BY `users`.`id` ASC LIMIT 1
=> 5
Of course, mysql hast its own query cache, so if the same query hits the database, it might be possible that the result is given back from the database query cache (you can see in the example above that the last queries takes less time than the first one, which probably is because mysq serves the results from its cache)

Active Record "Where" Query Failing to find Record

So have a token model that has keys which are strings. I am doing a search for a token that exists and when i do a direct comparrison of the string with the record it should find i get an empty active record relation object.
Anyone know what is going on here? Am i stepping on a models toes by using the Model name 'Token'. I didn't find anything in the googles about it.
I've stored the key as 'a' below and Token.last.key is the database entry that has the matching key.
irb(main):023:0> a
=> "279684d7488254c41bb4039ad0962007"
irb(main):024:0> Token.last.key
Token Load (0.4ms) SELECT "tokens".* FROM "tokens" ORDER BY "tokens"."id" DESC LIMIT 1
=> "279684d7488254c41bb4039ad0962007"
irb(main):025:0> a == Token.last.key
Token Load (0.1ms) SELECT "tokens".* FROM "tokens" ORDER BY "tokens"."id" DESC LIMIT 1
=> true
irb(main):026:0> Token.where(key: a)
Token Load (0.2ms) SELECT "tokens".* FROM "tokens" WHERE "tokens"."key" = '279684d7488254c41bb4039ad0962007'
=> #<ActiveRecord::Relation []>
irb(main):027:0> Token.where(key: a.to_s)
Token Load (0.2ms) SELECT "tokens".* FROM "tokens" WHERE "tokens"."key" = '279684d7488254c41bb4039ad0962007'
=> #<ActiveRecord::Relation []>
Oddly enough, when i do a search through all the records i do return the correct user
#DOES WORK
def current_user(key)
Token.all.first {|t| return t.key == key }
end
What i have will work but what i would like it to do this in the database with something like this
#DOES NOT WORK
def current_user(key)
Token.where(key: key).try(:user)
end
Doing search based on suggestion below returning nil for find_by
irb(main):004:0> a = Token.last.key
Token Load (0.2ms) SELECT "tokens".* FROM "tokens" ORDER BY "tokens"."id" DESC LIMIT 1
=> "279684d7488254c41bb4039ad0962007"
irb(main):005:0> Token.find_by(key: a)
Token Load (0.2ms) SELECT "tokens".* FROM "tokens" WHERE "tokens"."key" = '279684d7488254c41bb4039ad0962007' LIMIT 1
=> nil
Solution was to do this
def find_user_by_api(key)
tokens = Token.arel_table
Token.where(tokens[:key].matches(key)).try(:first).try(:user)
end
Wish it helps
Token.find_by(key: a)

creating seed data for a model not working

So I have a question model that belongs to User. Initially, I'd like to set basic questions with an attribute public: true, and every user can see this kind of questions which I'd like to create in the seed.rb.
Then, subsequently with an Answer model. Each users answer belongs to a certain question.
Now the issue is creating these pre-made questions for the users to answer I've tried the following in seed.rb:
u = User.new(email: "test#gmail.com", password: "testpass", password_confirmation: "testpass", gender: "M")
questions = u.questions.build(title: "What is your favourite food?")
u.save
And I'd like to call the same default questions for all users in the view with
questions_controller.rb
def index
#questions = Question.all
end
But this simply doesn't seem to be working, i.e. when I go to rails c and run u, it's an undefined method.. and the u.questions is an empty array. I've run these lines in console manually and they worked so I'm not sure what's happening here.
What am I doing wrong?
Update dev log
^[[1m^[[36mUser Load (16.9ms)^[[0m ^[[1mSELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT 1^[[0m
^[[1m^[[35mQuestion Load (645.9ms)^[[0m SELECT "questions".* FROM "questions" WHERE "questions"."user_id" = $1 [["user_id", 2]]
^[[1m^[[36mActiveRecord::SchemaMigration Load (48.4ms)^[[0m ^[[1mSELECT "schema_migrations".* FROM "schema_migrations"^[[0m
^[[1m^[[36mActiveRecord::SchemaMigration Load (1.0ms)^[[0m ^[[1mSELECT "schema_migrations".* FROM "schema_migrations"^[[0m
^[[1m^[[35m (0.3ms)^[[0m BEGIN
^[[1m^[[36mUser Exists (34.7ms)^[[0m ^[[1mSELECT 1 AS one FROM "users" WHERE "users"."email" = 'anthony#gmail.com' LIMIT 1^[[0m
^[[1m^[[35m (0.3ms)^[[0m ROLLBACK
DEPRECATION WARNING: You didn't set config.secret_key_base. Read the upgrade documentation to learn more about this new config option. (called from service a\
t /usr/local/rvm/rubies/ruby-2.0.0-p247/lib/ruby/2.0.0/webrick/httpserver.rb:138)
I think the issue was that the OP had bad data in the development database.
Running rake db:drop db:create db:setup appeared to fix the issue.

Spree/Rails user password reset

I'm trying to set user's (admin) password from Rails console:
bundle exec rails console
> Spree::User.first.email
=> "admin#mysite.com"
> Spree::User.first.encrypted_password
Spree::User Load (1.1ms) SELECT "spree_users".* FROM "spree_users" LIMIT 1
=> "4ec556............................................."
> Spree::User.first.password='spree123'
Spree::User Load (1.0ms) SELECT "spree_users".* FROM "spree_users" LIMIT 1
=> "spree123"
> Spree::User.first.password_confirmation='spree123'
Spree::User Load (1.0ms) SELECT "spree_users".* FROM "spree_users" LIMIT 1
=> "spree123"
> Spree::User.first.save!
Spree::User Load (1.0ms) SELECT "spree_users".* FROM "spree_users" LIMIT 1
(0.3ms) BEGIN
(1.3ms) SELECT COUNT(DISTINCT "spree_users"."id") FROM "spree_users" LEFT OUTER JOIN "spree_roles_users" ON "spree_roles_users"."user_id" = "spree_users"."id" LEFT OUTER JOIN "spree_roles" ON "spree_roles"."id" = "spree_roles_users"."role_id" WHERE "spree_roles"."name" = 'admin'
(0.3ms) COMMIT
=> true
> Spree::User.first.encrypted_password
Spree::User Load (1.0ms) SELECT "spree_users".* FROM "spree_users" LIMIT 1
=> "1bc15d.............................................."
So far so good. It looks like the new password for the user has been changed and commited to the database. However when I try to log in later with a web client and using the new password, it fails with invalid identity/password message.
I even tried to update password with Spree::User.first.reset_password!('spree123', 'spree123') but sill cann't sign in.
Rails 3.2.12
Spree 1.3.2
Any idea what am I doing wrong ? How to properly set a new password ?
Thanks.
The problem is that every time you're doing Spree::User.first it's reloading the record from the database. This means you are setting the value on one instance of the record, reloading it, and then saving the reloaded model that hasn't actually changed. An easy way around this is to create a local instance variable containing the record and update that instead:
user = Spree::User.first
user.password='spree123'
user.password_confirmation='spree123'
user.save!
Spree::User.first.update_attributes(password: 'password')

In Rails, why are these extra queries being run when saving a record?

In $ rails console I noticed that multiple queries are being run when I save a record:
ruby-1.9.2-p180 :001 > ActiveRecord::Base.logger = Logger.new(STDOUT)
=> #<...>
ruby-1.9.2-p180 :002 > p = Project.first
Project Load (0.3ms) SELECT `projects`.* FROM `projects` LIMIT 1
=> #<Project id: 1, category_id: 1, qualified_at: "2011-12-14 15:06:29", ...>
ruby-1.9.2-p180 :003 > p.qualified_at = Time.now
=> 2011-12-14 10:11:42 -0500
ruby-1.9.2-p180 :004 > p.save
SQL (0.2ms) BEGIN
SQL (1.5ms) SHOW TABLES
AREL (0.3ms) UPDATE `projects` SET `qualified_at` = '2011-12-14 15:11:42', `updated_at` = '2011-12-14 15:11:47' WHERE `projects`.`id` = 1
Category Load (0.3ms) SELECT `categories`.* FROM `categories` WHERE `categories`.`id` = 1 ORDER BY name LIMIT 1
ProjectPerson Load (0.4ms) SELECT `project_people`.* FROM `project_people` WHERE (`project_people`.project_id = 1 AND (project_people.is_client = 1)) LIMIT 1
Person Load (0.3ms) SELECT `people`.* FROM `people` WHERE (`people`.`id` = 2)
ProjectTag Load (0.4ms) SELECT DISTINCT `project_tags`.tag_id FROM `project_tags` WHERE (`project_tags`.project_id = 1)
SQL (0.5ms) COMMIT
=> true
I don't have before or after filters in my Project model, and I'm not using an Observer. Obviously these queries relate to associations of the Project model, but why are the queries being run? Not sure what else to consider. Thanks.
I just figured it out... I'm using the sunspot_rails gem and it was updating the index for that record :) These were associations that were referenced in my index definition.
I'll keep the question in case anyone else happens to come across a similar problem.

Resources