I try saving a row that has an attribute named class_datetime (which is a DateTime) and it silently fails. Here's an example:
I create a new LittleClassSession, like so:
irb(main):010:0> l = LittleClassSession.new
=> #<LittleClassSession id: nil, length: nil, class_datetime: nil, created_at: nil, updated_at: nil, little_class_id: nil, location_id: nil, session_series_token: nil>
The class_datetime is a DateTime:
irb(main):011:0> LittleClassSession.columns_hash["class_datetime"].type
=> :datetime
I set the attribute:
irb(main):012:0> l.class_datetime = DateTime.now
=> 2015-08-13 22:02:09 -0400
And I save (no validations yet):
irb(main):013:0> l.save
(0.1ms) begin transaction
SQL (0.4ms) INSERT INTO "little_class_sessions" ("class_datetime", "created_at", "updated_at") VALUES (?, ?, ?) [["class_datetime", "2015-08-13 22:02:09.976030"], ["created_at", "2015-08-13 22:03:01.255911"], ["updated_at", "2015-08-13 22:03:01.255911"]]
(2.6ms) commit transaction
=> true
Looks like it worked. Let's see what I saved:
irb(main):014:0> l
=> #<LittleClassSession id: 728, length: nil, class_datetime: "2015-08-14 02:02:09", created_at: "2015-08-14 02:03:01", updated_at: "2015-08-14 02:03:01", little_class_id: nil, location_id: nil, session_series_token: nil>
Let's see what's in the table:
irb(main):015:0> LittleClassSession.last
LittleClassSession Load (0.2ms) SELECT "little_class_sessions".* FROM "little_class_sessions" ORDER BY "little_class_sessions"."id" DESC LIMIT 1
=> #<LittleClassSession id: 728, length: nil, class_datetime: nil, created_at: nil, updated_at: nil, little_class_id: nil, location_id: nil, session_series_token: nil>
My LittleClassSession model looks like:
class LittleClassSession < ActiveRecord::Base
belongs_to :little_class
belongs_to :location
end
What could be causing this? Recently I changed the default timezone in application.rb, but I don't see why that might be the reason.
Your :date_time field is DateTime object.
Try this:
l.class_datetime = DateTime.now
Rather than:
l.class_datetime = Time.now
The issue went away once I removed these two lines from application.rb:
config.time_zone = 'Eastern Time (US & Canada)'
config.active_record.default_timezone = 'Eastern Time (US & Canada)'
This evidently caused some chaos.
Related
I'm new to activerecord and postgresql and I have the following issue with regards to a activerecord query. Please help me understand why this is happening and how I can resolve it.
I have multiple text columns which is declared in a standard way in my schema file.
create_table "time_entries", force: :cascade do |t|
t.string "user"
t.string "email"
etc ....
end
I'm trying to find records with 'user' = 'Test'.
TimeEntry.where(user: "Test")
works fine, however
TimeEntry.where("user = 'Test'")
does not work.
I can see that the two query yields different sql queries but I'm trying to understand why this works for the 'email' field but not for the 'user' field.
User Field Query:
irb(main):011:0> TimeEntry.where(user: "Test")
TimeEntry Load (0.5ms) SELECT "time_entries".* FROM "time_entries" WHERE "time_entries"."user" = $1 [["user", "Test"]]
=> #<ActiveRecord::Relation [#<TimeEntry id: 1, user: "Test", email: "test#testemail.com", task: nil, description: "TEST CRM", billable: "No", start_date: "2016-01-03", start_time: "2000-01-01 14:20:22", end_date: "2016-01-03", end_time: "2000-01-01 14:26:29", duration: "2000-01-01 00:06:07", tags: nil, amount: 111, created_at: "2017-01-03 15:39:51", updated_at: "2017-01-03 15:39:51", project_id: 1, resource_id: nil>]>
irb(main):012:0> TimeEntry.where("user = 'Test'")
TimeEntry Load (0.4ms) SELECT "time_entries".* FROM "time_entries" WHERE (user = 'Test')
=> #<ActiveRecord::Relation []>
irb(main):013:0>
Email Field Query:
irb(main):013:0> TimeEntry.where(email: "test#testemail.com")
TimeEntry Load (0.3ms) SELECT "time_entries".* FROM "time_entries" WHERE "time_entries"."email" = $1 [["email", "test#testemail.com"]]
=> #<ActiveRecord::Relation [#<TimeEntry id: 1, user: "Test", email: "test#testemail.com", task: nil, description: "TEST CRM", billable: "No", start_date: "2016-01-03", start_time: "2000-01-01 14:20:22", end_date: "2016-01-03", end_time: "2000-01-01 14:26:29", duration: "2000-01-01 00:06:07", tags: nil, amount: 111, created_at: "2017-01-03 15:39:51", updated_at: "2017-01-03 15:39:51", project_id: 1, resource_id: nil>]>
irb(main):014:0> TimeEntry.where("email = 'test#testemail.com'")
TimeEntry Load (0.4ms) SELECT "time_entries".* FROM "time_entries" WHERE (email = 'test#testemail.com')
=> #<ActiveRecord::Relation [#<TimeEntry id: 1, user: "Test", email: "test#testemail.com", task: nil, description: "TEST CRM", billable: "No", start_date: "2016-01-03", start_time: "2000-01-01 14:20:22", end_date: "2016-01-03", end_time: "2000-01-01 14:26:29", duration: "2000-01-01 00:06:07", tags: nil, amount: 111, created_at: "2017-01-03 15:39:51", updated_at: "2017-01-03 15:39:51", project_id: 1, resource_id: nil>]>
Thanks for your help.
Ok, seems this issue occurs due to 'user' being a reserved keyword in postgres.
The following code works fine:
TimeEntry.where('time_entries.user = ?', 'Test')
or
TimeEntry.where('"user" = ?','Test')
I have a method in my Rails User model that looks like this:
def prep_data
if email.present?
self.email = email.downcase
end
if username.present?
self.username = username.downcase
end
puts "***********************"
puts self.email
puts self.inspect
puts "***********************"
end
When I run this, I'm getting:
***********************
john#me.com
#<User id: nil, username: nil, email: nil, password_salt: nil, password_digest: nil, created_at: nil, updated_at: nil>
***********************
I'm at a loss to explain why self.email seems to be set, but then when I inspect self, it is nil. This is also causing the object to not save because it's nil. A more complete version of the log is
Processing by UsersController#create as HTML
Parameters: {"utf8"=>"✓","authenticity_token"=>"7ocuB7GiyPjMZ84SHKo9CDSPjY8uOdtDc5A9wr+stzTPrIHnvfxAkdp1HxWActd07ZWzJVEBH43A3V/4sX1ixg==", "user"=>{"username"=>"John", "email"=>"John#me.com", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Create User"}
(0.0ms) begin transaction
***********************
john#me.com
#<User id: nil, username: nil, email: nil, password_salt: nil, password_digest: nil, created_at: nil, updated_at: nil>
***********************
***********************
john#me.com
#<User id: nil, username: nil, email: nil, password_salt: "$2a$10$T92qOVBwjGm4t550POLVHu", password_digest: "$2a$10$T92qOVBwjGm4t550POLVHuXhss6lniJJekxMbeKR/yU...", created_at: nil, updated_at: nil>
***********************
User Exists (0.2ms) SELECT 1 AS one FROM "users" WHERE "users"."username" = 'john' LIMIT 1
User Exists (0.0ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = 'john#me.com' LIMIT 1
SQL (0.7ms) INSERT INTO "users" ("password_salt", "password_digest", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["password_salt", "$2a$10$T92qOVBwjGm4t550POLVHu"], ["password_digest", "$2a$10$T92qOVBwjGm4t550POLVHuXhss6lniJJekxMbeKR/yU.79uMqtZJa"], ["created_at", "2016-09-23 17:51:31.692923"], ["updated_at", "2016-09-23 17:51:31.692923"]]
SQLite3::ConstraintException: NOT NULL constraint failed: users.username: INSERT INTO "users" ("password_salt", "password_digest", "created_at", "updated_at") VALUES (?, ?, ?, ?)
The end goal is to get this to actually save. You can see that when rails does the Insert, username and email are nil, but I can tell from the debug puts statements that the email and username exist and are getting at least to the validation. That said, even it I remove the validation completely, I have this problem.
Have you tried this?
self.email.downcase! if email.present?
#arieljuod solved this for me by recommending that I use custom setters instead of trying to change things before validation. Problem solved although I don't fully understand why the other way didn't work even if it wasn't "best"
def username=(value)
self[:username] = value.downcase
end
def email=(value)
self[:email] = value.downcase
end
You need to call save on the model. So just call self.save on the model.
This is confusing me no end.
In a rake task, I am saving new records on the DailyScore model with the following code:
def save_record_as_daily_score_object(data)
#ds = DailyScore.where(date: data[:date]).first_or_create!
#ds.update!(data)
binding.pry
end
The pry output is as follows:
[10] pry(main)> data
=> {:date=>"2015-09-02",
:mail=>-0.6,
:times=>-7.1,
:telegraph=>-2.2,
:guardian=>-4.0,
:express=>-0.1,
:independent=>-3.2,
:average=>-3.4}
[11] pry(main)> #ds
=> #<DailyScore:0x000001098121a8
id: 4975,
mail: nil,
telegraph: nil,
times: nil,
average: nil,
guardian: nil,
independent: nil,
express: nil,
date: nil,
created_at: 2016-05-16 13:10:03 UTC,
updated_at: 2016-05-16 13:10:03 UTC>
[12] pry(main)> #ds.average
=> -3.4
[13] pry(main)> #ds.date
=> "2015-09-02"
[14] pry(main)> #ds.persisted?
=> true
[15] pry(main)> DailyScore.last
=> #<DailyScore:0x000001086810d8
id: 4975,
mail: nil,
telegraph: nil,
times: nil,
average: nil,
guardian: nil,
independent: nil,
express: nil,
date: nil,
created_at: 2016-05-16 13:10:03 UTC,
updated_at: 2016-05-16 13:10:03 UTC>
[16] pry(main)> DailyScore.last.average
=> nil
What is going on here? Why can't Pry access my variable attributes? And is the record actually being saved or not?
UPDATE:
Checking in the console, the behaviour is the same if I simply create a new object. I'm using the Padrino framework, and a Postgres db.
2.0.0 :001 > ds = DailyScore.new(date:"2016-01-01")
=> #<DailyScore id: nil, mail: nil, telegraph: nil, times: nil, average: nil, guardian: nil, independent: nil, express: nil, date: nil, created_at: nil, updated_at: nil>
2.0.0 :002 > ds.date
=> "2016-01-01"
2.0.0 :003 > ds
=> #<DailyScore id: nil, mail: nil, telegraph: nil, times: nil, average: nil, guardian: nil, independent: nil, express: nil, date: nil, created_at: nil, updated_at: nil>
Is it a problem with the model? Here is the original migration:
006_create_daily_scores.rb
class CreateDailyScores < ActiveRecord::Migration
def self.up
create_table :daily_scores do |t|
t.float :average
t.datetime :date
t.float :express
t.float :independent
t.float :guardian
t.float :telegraph
t.float :mail
t.float :times
t.timestamps
end
end
def self.down
drop_table :daily_scores
end
end
Have now added another column day:date - using :date instead of :datetime - to check if it was a quirk with :datetime, but behaviour is the same.
This happens because you called attr_accessor in your model with your model attributes, which overrode default accessors provided by Rails (the accessors are called by update and new methods). Note this doc, for reference, if you do want to override accessors one day.
Removing attr_accessor from your model will do the trick!
Hi i have the following situation. I can save this array of hashes
products = [{
:name=> 0,
:key => 12345,
:label => "test1",
},{
:name=> 0,
:key => 12145,
:label => "test",
}]
at once with
products.map {|p| Product.new(p).save }
or
Product.create(products)
Product.create!(products)
but the all my uniqueness validations like
validates :key, presence: true, uniqueness: true
are ignored, using the rails console. I am able to save this hash multiple times. Does anyone has some advice? Thanks in advance!
SOLUTION
As simple as restarting my rails console. After that my logs look like the logs from #Akadisoft.
Also using this way:
products.map {|p| Product.new(p).save }
which return an array with booleans [false,true] either the record was saved or not, which is nice for further evaluation.
I have tried your exact solution and everything works as intented..
The first time I ran the command Product.create(products) I have the following result
=> #<ActiveRecord::Relation [#<Product id: 1, key: "12345", name: 0, label: "test1", created_at: "2015-12-09 19:21:01", updated_at: "2015-12-09 19:21:01">, #<Product id: 2, key: "12145", name: 0, label: "test", created_at: "2015-12-09 19:21:01", updated_at: "2015-12-09 19:21:01">]>
We can see that it created two products (id:1 and id:2).
Now the second I run the exact same command here is the result:
[#<Product id: nil, key: "12345", name: 0, label: "test1", created_at: nil, updated_at: nil>, #<Product id: nil, key: "12145", name: 0, label: "test", created_at: nil, updated_at: nil>]
irb(main):015:0>
We can see the ID is nil because it didn't save the products. I can also see in the console output that DB transaction were rollbacked.
I tried this on console and it only added one record.
14:42 $ rails c
Loading development environment (Rails 4.2.5)
2.2.2 :001 > products = [{:key =>1},{:key=>1}]
=> [{:key=>1}, {:key=>1}]
2.2.2 :002 > products.map {|p| Product.new(p).save }
(0.1ms) begin transaction
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."key" = 1 LIMIT 1
SQL (0.8ms) INSERT INTO "products" ("key", "created_at", "updated_at") VALUES (?, ?, ?) [["key", 1], ["created_at", "2015-12-09 19:42:32.488255"], ["updated_at", "2015-12-09 19:42:32.488255"]]
(0.4ms) commit transaction
(0.0ms) begin transaction
Product Exists (0.1ms) SELECT 1 AS one FROM "products" WHERE "products"."key" = 1 LIMIT 1
(0.0ms) rollback transaction
=> [true, false]
2.2.2 :003 > Product.all
Product Load (0.2ms) SELECT "products".* FROM "products"
=> #<ActiveRecord::Relation [#<Product id: 1, key: 1, created_at: "2015-12-09 19:42:32", updated_at: "2015-12-09 19:42:32">]>
I have a model spec that is failing with "undefined method 'save' for nil:NilClass'." This occurs in the class method 'create_and_send_self_eval'. The method is creating a new Evaluation, but it always returns nil in the test environment. I've also tried using 'create', 'create!' and they also return nil. However, this only occurs in the test environment. In the development environment, it returns the correct object. I'm using rspec 3.1.5, rails 4.1.6, and ruby 2.1.2.
I've included the code for the class and my debug output. Any suggestions?
Evaluation.rb
class Evaluation < ActiveRecord::Base
has_one :evaluator
validates_uniqueness_of :access_key
validates_presence_of :participant_id
before_validation :set_access_key, on: :create
def send_invite
return true
end
def self.create_and_send_self_eval(participant)
evaluation = self.new do |e|
e.participant_id = participant.id
e.evaluator = participant
end
if evaluation.nil?
binding.pry
end
evaluation.save
end
private
def set_access_key
return if access_key.present?
begin
self.access_key = SecureRandom.hex(8)
end while self.class.exists?(access_key: self.access_key)
end
end
Debug output using pry in the test environment
[1] pry(Evaluation)> participant
=> #<Participant id: 167, first_name: "Puff", last_name: "Daddy", evaluation_url: nil, created_at: "2014-10-07 19:43:47", updated_at: "2014-10-07 19:43:47">
[2] pry(Evaluation)> Evaluation.new
=> nil
[3] pry(Evaluation)> Evaluation.create(participant_id: participant.id)
NoMethodError: undefined method `save' for nil:NilClass
from /Users/diyahm/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.6/lib/active_record/persistence.rb:34:in `create'
[4] pry(Evaluation)> Evaluation.create!(participant_id: participant.id)
NoMethodError: undefined method `save!' for nil:NilClass
from /Users/diyahm/.rvm/gems/ruby-2.1.2/gems/activerecord-4.1.6/lib/active_record/validations.rb:41:in `create!'
Debug output in rails console
2.1.2 :005 > p = Participant.last
SQL (0.9ms) SELECT "participants"."id" AS t0_r0, "participants"."first_name" AS t0_r1, "participants"."last_name" AS t0_r2, "participants"."evaluation_url" AS t0_r3, "participants"."created_at" AS t0_r4, "participants"."updated_at" AS t0_r5, "evaluators"."id" AS t1_r0, "evaluators"."email" AS t1_r1, "evaluators"."created_at" AS t1_r2, "evaluators"."updated_at" AS t1_r3, "evaluators"."actable_id" AS t1_r4, "evaluators"."actable_type" AS t1_r5, "evaluators"."evaluation_id" AS t1_r6 FROM "participants" LEFT OUTER JOIN "evaluators" ON "evaluators"."actable_id" = "participants"."id" AND "evaluators"."actable_type" = 'Participant' ORDER BY "participants"."id" DESC LIMIT 1
=> #<Participant id: 3, first_name: "Puff", last_name: "Daddy", evaluation_url: nil, created_at: "2014-10-06 06:32:40", updated_at: "2014-10-06 06:32:40">
2.1.2 :006 > Evaluation.new
=> #<Evaluation id: nil, participant_id: nil, access_key: nil, created_at: nil, updated_at: nil>
2.1.2 :007 > Evaluation.create(participant_id: p.id)
(0.2ms) BEGIN
Evaluation Exists (2.1ms) SELECT 1 AS one FROM "evaluations" WHERE "evaluations"."access_key" = 'c688b05ee4625c60' LIMIT 1
Evaluation Exists (0.3ms) SELECT 1 AS one FROM "evaluations" WHERE "evaluations"."access_key" = 'c688b05ee4625c60' LIMIT 1
SQL (1.7ms) INSERT INTO "evaluations" ("access_key", "created_at", "participant_id", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["access_key", "c688b05ee4625c60"], ["created_at", "2014-10-07 19:47:15.877706"], ["participant_id", 3], ["updated_at", "2014-10-07 19:47:15.877706"]]
(2.3ms) COMMIT
=> #<Evaluation id: 4, participant_id: 3, access_key: "c688b05ee4625c60", created_at: "2014-10-07 19:47:15", updated_at: "2014-10-07 19:47:15">
pry debug output at beginning of method
[1] pry(Evaluation)> self
=> Evaluation(id: integer, participant_id: integer, access_key: string, created_at: datetime, updated_at: datetime)
[2] pry(Evaluation)> self.class
=> Class
[3] pry(Evaluation)> self.connection
=> #<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter:0x007f8158eb8ee0
[4] pry(Evaluation)> Evaluation
=> Evaluation(id: integer, participant_id: integer, access_key: string, created_at: datetime, updated_at: datetime)
[5] pry(Evaluation)> Evaluation.class
=> Class
[6] pry(Evaluation)> Evaluation.connection
=> #<ActiveRecord::ConnectionAdapters::PostgreSQLAdapter:0x007f8158eb8ee0
I didn't show the entire output for self.connection or Evaluation.connection. But connection is returning correctly.
The answer to this question had to do with how the tests were written. In my spec, I'm checking to see if "new" is called on Evaluation. Since, I'm using rspec-mocks, Evaluation is not actually being created. Fixed this by changing the test to test the output results.
Try doing this instead:
evaluation = self.new.tap do |e|
e.participant_id = participant.id
e.evaluator = participant
end
Using Object#tap should guarantee that you set evaluation to the object rather than to the return value of the block.