rails : association :undefined method `title' for nil:NilClass - ruby-on-rails

A 'page' may have_many 'sections'. So I want to retrieve the 'sections.title' for each 'sections' that a page contains. I don't understand why my block Do doesn't work but this works sections.each { |n| p n.id }
2.0.0-p353 :041 > pages = Page.find(52).sections.count
Page Load (0.3ms) SELECT `pages`.* FROM `pages` WHERE `pages`.`id` = 52 LIMIT 1
(0.3ms) SELECT COUNT(*) FROM `sections` WHERE `sections`.`page_id` = 52
=> 2
2.0.0-p353 :042 > pages =Page.find(52).sections
Page Load (0.3ms) SELECT `pages`.* FROM `pages` WHERE `pages`.`id` = 52 LIMIT 1
Section Load (0.2ms) SELECT `sections`.* FROM `sections` WHERE `sections`.`page_id` = 52
=> #<ActiveRecord::Associations::CollectionProxy [#<Section id: 20, title: "La victoire est proche", body: "Guinsly t'e le meilleur Oat cake sweet roll browni...", page_id: 52, created_at: "2014-01-22 01:40:14", updated_at: "2014-01-22 01:40:14">, #<Section id: 36, title: "La victoire est proche", body: "Guinsly t'e le meilleur Oat cake sweet roll browni...", page_id: 52, created_at: "2014-01-22 01:40:15", updated_at: "2014-01-22 01:40:15">]>
2.0.0-p353 :044 > pages.each do |n|
2.0.0-p353 :045 > p.title
2.0.0-p353 :046?> end
NoMethodError: undefined method `title' for nil:NilClass
or
...
2.0.0-p353 :055 > Page.find(52).sections.each { |n| p n.id }
Page Load (0.3ms) SELECT `pages`.* FROM `pages` WHERE `pages`.`id` = 52 LIMIT 1
Section Load (0.3ms) SELECT `sections`.* FROM `sections` WHERE `sections`.`page_id` = 52
20
36

Your each block is looking for you to use n not p...
pages.each do |n|
n.title
end
Though p makes more sense, you might use p instead of n in both places.
Or are you trying to print the value using the p method? Then:
pages.each do |page|
p page.title
end

Related

Rails ActiveJob showing outdated DB data

Problem I'm trying to solve:
Multiple projects connect/make updates to the same DB. "Project A" is tasked with making updates to the DB, "Project B" is the client interface, tasked with showing updated data.
Solution:
When Project A is scheduled to update records, Project B will create a background Job to run for 15 minutes to catch the updates made, updating the interface every 15 seconds via ActionCable (webhooks).
Issue:
ActiveJob is stuck on "3 remaining records" without noticing any DB changes. If the Model is called directly (outside of the Job), everything works as expected; DB changes are noticed, client interface gets updated, and everyone is happy.
But as soon as it's called from the Job (to run the task in the background), it gets stuck.
Job that calls the Model logic:
class BatchWatchJob < ApplicationJob
queue_as :default
def perform(**args)
if args[:batch_number]
p "=== Begin - BatchWatch for batch_number: #{args[:batch_number]} ==="
begin
# Set 15 minute timeout
# ReImport.watch_batch() not updating
# it's count when DB data changes :/
# BUT if I call the method directly (not from this Job), it works
Timeout.timeout(900) { ReImport.watch_batch(args[:batch_number]) }
rescue Timeout::Error
puts '=== TIMEOUT ERROR ==='
puts 'BatchWatch job failed to finish in the requisite amount of time (15 minutes)'
end
else
p "=== Unable to start BatchWatch, batch_number not specified ==="
end
end
end
Model containing my logic:
class ReImport < ApplicationRecord
[...]
def self.watch_batch(num)
batch = ReImport.where(batch: num)
total = batch.count
remaining = batch.where(completed: false) # NOTE: starts with 3 remaining
remaining_count = remaining.count
p "initial remaining: #{remaining_count}"
while !remaining.empty? do
p 'wait 10 seconds...'
sleep(10) # wait 10 seconds
p '...seconds finished...'
# batch.reload # doesn't work
# remaining.reload # doesn't work
batch = ReImport.where(batch: num)
remaining = batch.where(completed: false) # NOTE: this should now be 2
p "remaining_count: #{remaining_count}"
p "remaining . count: #{remaining.count}"
p "(remaining_count > remaining.count): #{(remaining_count > remaining.count)}"
if remaining_count > remaining.count
p '=== WATCH_BATCH: update found! ==='
# Update count
remaining_count = remaining.count
# Broadcast DataTables to update records
ReImportBatchChannel.broadcast_to("re_import_batch_#{num}", {update: true})
else
p '=== WATCH_BATCH: nothing changed yet ==='
end
end
p '=== WATCH_BATCH COMPLETED (or timeout reached) ==='
end
[...]
end
Rails Console - Output:
> BatchWatchJob.perform_later(batch_number: 7)
Enqueued BatchWatchJob (Job ID: 7d1beeaf-c4d8-4489-885c-13b44d1037cf) to Async(default) with arguments: {:batch_number=>7}
=> #<BatchWatchJob:0x000000055c2100 #arguments=[{:batch_number=>7}], #job_id="7d1beeaf-c4d8-4489-885c-13b44d1037cf", #queue_name="default", #priority=nil, #executions=0, #provider_job_id="011e004c-34f5-4c7a-9925-052df1aa1774">
Performing BatchWatchJob (Job ID: 7d1beeaf-c4d8-4489-885c-13b44d1037cf) from Async(default) with arguments: {:batch_number=>7}
"=== Begin - BatchWatch for batch_number: 7 ==="
(2.1ms) SET ##SESSION.sql_mode = CONCAT(CONCAT(##sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), ##SESSION.sql_auto_is_null = 0, ##SESSION.wait_timeout = 2147483
(0.9ms) SELECT COUNT(*) FROM `re_imports` WHERE `re_imports`.`batch` = 7
(0.7ms) SELECT COUNT(*) FROM `re_imports` WHERE `re_imports`.`batch` = 7 AND `re_imports`.`completed` = 0
"initial remaining: 3"
ReImport Exists (0.5ms) SELECT 1 AS one FROM `re_imports` WHERE `re_imports`.`batch` = 7 AND `re_imports`.`completed` = 0 LIMIT 1
"wait 10 seconds..."
"...seconds finished..."
"remaining_count: 3"
CACHE (0.0ms) SELECT COUNT(*) FROM `re_imports` WHERE `re_imports`.`batch` = 7 AND `re_imports`.`completed` = 0 [["batch", 7], ["completed", 0]]
"remaining . count: 3"
CACHE (0.0ms) SELECT COUNT(*) FROM `re_imports` WHERE `re_imports`.`batch` = 7 AND `re_imports`.`completed` = 0 [["batch", 7], ["completed", 0]]
"(remaining_count > remaining.count): false"
CACHE (0.0ms) SELECT COUNT(*) FROM `re_imports` WHERE `re_imports`.`batch` = 7 AND `re_imports`.`completed` = 0 [["batch", 7], ["completed", 0]]
"=== WATCH_BATCH: nothing changed yet ==="
CACHE ReImport Exists (0.0ms) SELECT 1 AS one FROM `re_imports` WHERE `re_imports`.`batch` = 7 AND `re_imports`.`completed` = 0 LIMIT 1 [["batch", 7], ["completed", 0], ["LIMIT", 1]]
"wait 10 seconds..."
"...seconds finished..."
"remaining_count: 3"
CACHE (0.0ms) SELECT COUNT(*) FROM `re_imports` WHERE `re_imports`.`batch` = 7 AND `re_imports`.`completed` = 0 [["batch", 7], ["completed", 0]]
"remaining . count: 3"
CACHE (0.0ms) SELECT COUNT(*) FROM `re_imports` WHERE `re_imports`.`batch` = 7 AND `re_imports`.`completed` = 0 [["batch", 7], ["completed", 0]]
"(remaining_count > remaining.count): false"
CACHE (0.0ms) SELECT COUNT(*) FROM `re_imports` WHERE `re_imports`.`batch` = 7 AND `re_imports`.`completed` = 0 [["batch", 7], ["completed", 0]]
"=== WATCH_BATCH: nothing changed yet ==="
CACHE ReImport Exists (0.0ms) SELECT 1 AS one FROM `re_imports` WHERE `re_imports`.`batch` = 7 AND `re_imports`.`completed` = 0 LIMIT 1 [["batch", 7], ["completed", 0], ["LIMIT", 1]]
"wait 10 seconds..."
[...]
Performed BatchWatchJob (Job ID: 7d1beeaf-c4d8-4489-885c-13b44d1037cf) from Async(default) in 22863.44ms
I'm not just noticing CACHE ReImport Exists, trying to figure out how to turn that off...
I found that the problem is SQL Caching, and fixed it by using ActiveRecords uncached method ReImport.uncached do within the while loop like so:
Model
class ReImport < ApplicationRecord
[...]
def self.watch_batch(num)
batch = ReImport.where(batch: num)
total = batch.count
remaining = batch.where(completed: false)
remaining_count = remaining.count
p "initial remaining: #{remaining_count}"
while !remaining.empty? do
ReImport.uncached do # <--- UNCACHE SQL QUERIES
p 'wait 10 seconds...'
sleep(10) # wait 10 seconds
p '...seconds finished...'
batch = ReImport.where(batch: num)
remaining = batch.where(completed: false)
p "remaining_count: #{remaining_count}"
p "remaining . count: #{remaining.count}"
p "(remaining_count > remaining.count): #{(remaining_count > remaining.count)}"
if remaining_count > remaining.count
p '=== WATCH_BATCH: update found! ==='
# Update count
remaining_count = remaining.count
# Broadcast DataTables to update records
ReImportBatchChannel.broadcast_to("re_import_batch_#{num}", {update: true})
else
p '=== WATCH_BATCH: nothing changed yet ==='
end
end
end
p '=== WATCH_BATCH COMPLETED (or timeout reached) ==='
end
[...]
end
Source

Rails sum on AssociationRelation attribute is incorrect if association has limit clause

I have a method that computes stats (mainly sums) on a number of float attributes in a model.
The models
class GroupPlayer < ActiveRecord::Base
belongs_to :group
has_many :scored_rounds
has_many :rounds, dependent: :destroy
end
class Round < ActiveRecord::Base
belongs_to :group_player
end
class ScoredRound < Round
# STI
end
The method that provides stats on up to 4 float attributes that is called from a other methods, depending if I'm getting stats for one player or a group of players. An initial filter on ScoredRound is passed to the method (sr)
def method_stats(method,sr,grp)
rounds = sr.where.not(method => nil)
number_rounds = rounds.count
won = rounds.sum(method).round(2)
if method == :quality
dues = grp.options[:dues] * number_rounds
else
dues = grp.options["#{method.to_s}_dues"] * number_rounds
end
balance = (won - dues).round(2)
perc = dues > 0 ? (won / dues).round(3) : 0.0
[self.full_name,number_rounds,won,dues,balance,perc]
end
3 of the 4 attributes I am summing in ScoredRounds may not be set (nil) if the player did not win that game so the rounds are filtered.
Everything worked fine until I decided to add a limit on how many rounds to use. For instance if I only wanted status for the last 25 rounds in the query passed to method_stats I'd call:
def money_stats(grp,method,limit=100)
sr = self.scored_rounds.where.not(method => nil).order(:date).reverse_order.limit(limit)
method_stats(method,sr,grp)
end
Again, I just added the limit and order clause to the query. Worked fine for all records.
If I simulate the procedure in the console with out using the above methods (or using them!) I'll get an erroneous sum
gp = GroupPlayer.find(123)
GroupPlayer Load (2.1ms) SELECT "group_players".* FROM "group_players" WHERE "group_players"."id" = $1 LIMIT $2 [["id", 123], ["LIMIT", 1]]
=> valid group player
sr = gp.scored_rounds.where.not(:quality => nil)
ScoredRound Load (1.7ms) SELECT "rounds".* FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) [["group_player_id", 123]]
=> #<ActiveRecord::AssociationRelation [#<ScoredRound id: 5706, player_id: 123, group_player_id: 123, event_id: 12, type: "ScoredRound", date: "2016-11-04", team: 3, tee: "White", quota: 32, front: 15, back: 15, total: 30, created_at: "2016-11-04 14:18:27", updated_at: "2016-11-04 19:12:47", quality: 0.0, skins: nil, par3: nil, other: nil>,...]
sr.count
(1.5ms) SELECT COUNT(*) FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) [["group_player_id", 123]]
=> 44
sr.sum(:quality)
(1.0ms) SELECT SUM("rounds"."quality") FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) [["group_player_id", 123]]
=> 354.166666666667
# Now if I add the order and limit clause
sr = gp.scored_rounds.where.not(:quality => nil).order(:date).reverse_order.limit(25)
ScoredRound Load (1.6ms) SELECT "rounds".* FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) ORDER BY "rounds"."date" DESC LIMIT $2 [["group_player_id", 123], ["LIMIT", 25]]
=> => #<ActiveRecord::AssociationRelation [...]
sr.count
(1.1ms) SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) LIMIT $2) subquery_for_count [["group_player_id", 123], ["LIMIT", 25]]
=> 25
sr.sum(:quality)
(1.8ms) SELECT SUM("rounds"."quality") FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) LIMIT $2 [["group_player_id", 123], ["LIMIT", 25]]
=> 354.166666666667
### This is the error, it return the sum off all records,
# not the limited???? if I use pluck and sum
sr.pluck(:quality)
=> [10.0, 11.3333333333333, 10.0, 34.0, 0.0, 7.33333333333333, 0.0, 0.0, 31.5, 0.0, 21.3333333333333, 0.0, 19.0, 0.0, 0.0, 7.5, 0.0, 20.0, 10.0, 28.0, 8.0, 9.5, 0.0, 3.0, 24.0]
sr.pluck(:quality).sum
=> 254.49999999999994
Don't know if I found a bug in AREL or I'm doing something wrong. I tried it with just Round instead of the STI ScoredRound with the same results.
Any ideas?
If you notice, the SUM results for both, with and without LIMIT, are the same:
sr = gp.scored_rounds.where.not(:quality => nil)
sr.sum(:quality)
(1.0ms) SELECT SUM("rounds"."quality") FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) [["group_player_id", 123]]
=> 354.166666666667
sr = gp.scored_rounds.where.not(:quality => nil).order(:date).reverse_order.limit(25)
sr.sum(:quality)
(1.8ms) SELECT SUM("rounds"."quality") FROM "rounds" WHERE "rounds"."type" IN ('ScoredRound') AND "rounds"."group_player_id" = $1 AND ("rounds"."quality" IS NOT NULL) LIMIT $2 [["group_player_id", 123], ["LIMIT", 25]]
=> 354.166666666667
That's because LIMIT affects the number of rows returned by the query and SUM returns just one, so the function is applied for all the 44 records, not the 25 given to LIMIT. That's not what happens with sr.pluck(:quality).sum which applies only to the 25 records returned by the query.
Don't know if I found a bug in AREL or I'm doing something wrong
Sadly, 99.9% of times is not a bug but our fault :(
# File activerecord/lib/active_record/relation/calculations.rb, line 75
def sum(column_name = nil)
return super() if block_given?
calculate(:sum, column_name)
end
if you call sr.sum(:quality) then sum take quality as a column name and Calculates the sum of values on a given column.

How to make update a few rows in the table one minimalnym number of database queries

Have a collection of categories, represented as collections of objects. Each object has a sort property. This property takes a numeric value from 1 to the number which is the last element of the collection. There is a list of categories filtered by the sort property
linecategories=Linecategory.eager_load(:main_image).order('sort')
Then this list is dragged drag and drap and a certain number of objects to the collection is changing the value of this property sort. Further ajax goes from 2 to n of objects whose properties of the sort has changed.
Task to do update the changed fields in the database.
Now data comes in the form of:
data={}
data['items']=params[:data]
Where data has the form
data: [{id: 1, name: "Гороскопы", slug: "horoscopes", title: "keywords-horoscopes",…},…]
0: {id: 1, name: "Гороскопы", slug: "horoscopes", title: "keywords-horoscopes",…}
created_at: "2015-01-10T21:14:56.000Z"
description: "description-horoscopes"
id: 1
keywords: "keywords-horoscopes"
name: "Гороскопы"
slug: "horoscopes"
sort: 1
title: "keywords-horoscopes"
updated_at: "2015-07-19T19:10:03.000Z"
1: {id: 5, name: "Гадания", slug: "divination", title: "eywords-divination",…}
created_at: "2015-01-11T08:47:10.000Z"
description: "2015-01-11 08:47:10"
id: 5
keywords: "description-divination"
main_image: {id: 1, src: "images/categories_images/devination.jpg", linecategory_id: 5, created_at: null,…}
name: "Гадания"
slug: "divination"
sort: 2
title: "eywords-divination"
updated_at: "2015-07-19T19:24:23.000Z"
2: {id: 3, name: "Вкусности", slug: "delicious", title: "keywords-delicious",…}
created_at: "2015-01-10T21:17:28.000Z"
description: "2015-01-10 21:17:28"
id: 3
keywords: "description-delicious"
name: "Вкусности"
slug: "delicious"
sort: 3
title: "keywords-delicious"
updated_at: "2015-07-19T19:24:23.000Z"
Now I implemented the update like so:
def updates
data={}
data['items']=params[:data]
data['items'].each { |el|
#item=Linecategory.find(el['id'])
#item.update_attributes(el.permit(:sort))
}
render json: {update: 1, data: data['items']}
end
But I think it is not the optimal solution, I think it can be done more efficiently and more beautiful by means of ruby on rails and activerecords whether this is so, and if possible suggest solutions to the problem?
def updates
data=params[:data].as_json(only: [:id, :sort])
h = {}
data.each_with_index { |e, i| h[e['id']] = e }
Linecategory.update(h.keys, h.values)
render json: {update: 1, data: h}
end
Mine has found solutions, I still don't katsa completely optimal, since before the update I have to use:
data.each_with_index { |e, i| h[e['id']] = e }
but even so it works.
Plausible queries to update the database continues to be set, but girlfriend can do it?
Linecategory Load (0.4ms) SELECT `linecategories`.* FROM `linecategories` WHERE `linecategories`.`id` = 6 LIMIT 1
(0.3ms) BEGIN
Linecategory Exists (0.4ms) SELECT 1 AS one FROM `linecategories` WHERE (`linecategories`.`slug` = BINARY 'our_dreams' AND `linecategories`.`id` != 6) LIMIT 1
SQL (0.2ms) UPDATE `linecategories` SET `sort` = 1, `updated_at` = '2015-07-20 21:07:47' WHERE `linecategories`.`id` = 6
(2.3ms) COMMIT
Linecategory Load (0.5ms) SELECT `linecategories`.* FROM `linecategories` WHERE `linecategories`.`id` = 4 LIMIT 1
(0.3ms) BEGIN
Linecategory Exists (0.7ms) SELECT 1 AS one FROM `linecategories` WHERE (`linecategories`.`slug` = BINARY 'beauty_and_health' AND `linecategories`.`id` != 4) LIMIT 1
SQL (0.3ms) UPDATE `linecategories` SET `sort` = 2, `updated_at` = '2015-07-20 21:07:47' WHERE `linecategories`.`id` = 4
(1.0ms) COMMIT
Linecategory Load (0.2ms) SELECT `linecategories`.* FROM `linecategories` WHERE `linecategories`.`id` = 1 LIMIT 1
(0.2ms) BEGIN
Linecategory Exists (0.7ms) SELECT 1 AS one FROM `linecategories` WHERE (`linecategories`.`slug` = BINARY 'horoscopes' AND `linecategories`.`id` != 1) LIMIT 1
SQL (0.2ms) UPDATE `linecategories` SET `sort` = 3, `updated_at` = '2015-07-20 21:07:47' WHERE `linecategories`.`id` = 1
(0.9ms) COMMIT
Linecategory Load (0.4ms) SELECT `linecategories`.* FROM `linecategories` WHERE `linecategories`.`id` = 2 LIMIT 1
(0.3ms) BEGIN
Linecategory Exists (0.4ms) SELECT 1 AS one FROM `linecategories` WHERE (`linecategories`.`slug` = BINARY 'test_yourself' AND `linecategories`.`id` != 2) LIMIT 1
SQL (0.5ms) UPDATE `linecategories` SET `sort` = 4, `updated_at` = '2015-07-20 21:07:48' WHERE `linecategories`.`id` = 2
(0.9ms) COMMIT
Linecategory Load (0.3ms) SELECT `linecategories`.* FROM `linecategories` WHERE `linecategories`.`id` = 5 LIMIT 1
(0.2ms) BEGIN
Linecategory Exists (0.5ms) SELECT 1 AS one FROM `linecategories` WHERE (`linecategories`.`slug` = BINARY 'divination' AND `linecategories`.`id` != 5) LIMIT 1
SQL (0.2ms) UPDATE `linecategories` SET `sort` = 5, `updated_at` = '2015-07-20 21:07:48' WHERE `linecategories`.`id` = 5
(0.8ms) COMMIT
Linecategory Load (0.3ms) SELECT `linecategories`.* FROM `linecategories` WHERE `linecategories`.`id` = 7 LIMIT 1
(0.1ms) BEGIN
Linecategory Exists (0.4ms) SELECT 1 AS one FROM `linecategories` WHERE (`linecategories`.`slug` = BINARY 'what_is_it_in_my_name' AND `linecategories`.`id` != 7) LIMIT 1
SQL (0.2ms) UPDATE `linecategories` SET `sort` = 6, `updated_at` = '2015-07-20 21:07:48' WHERE `linecategories`.`id` = 7
(0.9ms) COMMIT
Linecategory Load (0.3ms) SELECT `linecategories`.* FROM `linecategories` WHERE `linecategories`.`id` = 3 LIMIT 1
(0.2ms) BEGIN
Linecategory Exists (0.4ms) SELECT 1 AS one FROM `linecategories` WHERE (`linecategories`.`slug` = BINARY 'delicious' AND `linecategories`.`id` != 3) LIMIT 1
SQL (0.3ms) UPDATE `linecategories` SET `sort` = 7, `updated_at` = '2015-07-20 21:07:48' WHERE `linecategories`.`id` = 3
(1.0ms) COMMIT
I found better method
# /admin_categories PUT
def updates
data=params[:data].as_json(only: [:id, :sort])
db = ActiveRecord::Base.connection()
ids=[]
query = "UPDATE linecategories SET sort = CASE id "
data.each_with_index do |e, i|
query += ActiveRecord::Base.send(:sanitize_sql_array,["WHEN ? THEN ? ", e['id'], e['sort']])
ids.push e['id']
end
query += "END "
query += "WHERE id in (#{ids.join(",")}) "
db.execute(query)
render json: {}
end

Why would the same identical SQL queries return a different result?

I have two ActiveRecord queries. One returns 4 which is the right number, and the other returns 11, which is the wrong count. I would have expected both queries to return 4. Even the SQL rendered in Rails console are identical for both AR queries.
First query:
campaign.daily_statistics.select('COUNT(DISTINCT user_id) AS count').where(metric: metric).where("properties -> '#{column}' = '#{value}'")[0]['count']
DailyStatistic Load (0.7ms) SELECT COUNT(DISTINCT user_id) AS count FROM "daily_statistics" WHERE "daily_statistics"."campaign_id" = $1 AND "daily_statistics"."metric" = 'participation' AND (properties -> 'assumed_gender' = 'female') [["campaign_id", 2]]
=> 4
Second query:
sql = campaign.daily_statistics.select('COUNT(DISTINCT user_id) AS count')
sql.where(metric: metric).where("properties -> '#{column}' = '#{value}'")
sql[0]['count']
DailyStatistic Load (0.9ms) SELECT COUNT(DISTINCT user_id) AS count FROM "daily_statistics" WHERE "daily_statistics"."campaign_id" = $1 AND "daily_statistics"."metric" = 'participation' AND (properties -> 'assumed_gender' = 'female') [["campaign_id", 2]]
=> 11
Can someone explain what is going on here?
In your second query, you're not assigning
sql.where(metric: metric).where("properties -> '#{column}' = '#{value}'")
to anything. So when you then run
sql[0]['count']
you're only executing the first part of the query that you assigned to the sql variable.
I'm not sure why the SQL logging output appears as it does. At a guess, it's due to some of the peculiarities of the rails console and when it provides output/inline logging.
What you should be seeing in the rails console is something like:
sql = campaign.daily_statistics.select('COUNT(DISTINCT user_id) AS count')
DailyStatistic Load (0.9ms) SELECT COUNT(DISTINCT user_id) AS count FROM "daily_statistics" WHERE "daily_statistics"."campaign_id" = $1) [["campaign_id", 2]]
sql.where(metric: metric).where("properties -> '#{column}' = '#{value}'")
DailyStatistic Load (0.9ms) SELECT COUNT(DISTINCT user_id) AS count FROM "daily_statistics" WHERE "daily_statistics"."campaign_id" = $1 AND "daily_statistics"."metric" = 'participation' AND (properties -> 'assumed_gender' = 'female') [["campaign_id", 2]]
sql[0]['count']
#=> 11
a fix for the 2nd query should be would be:
sql = campaign.daily_statistics.select('COUNT(DISTINCT user_id) AS count')
DailyStatistic Load (0.9ms) SELECT COUNT(DISTINCT user_id) AS count FROM "daily_statistics" WHERE "daily_statistics"."campaign_id" = $1) [["campaign_id", 2]]
sql2 = sql.where(metric: metric).where("properties -> '#{column}' = '#{value}'")
DailyStatistic Load (0.9ms) SELECT COUNT(DISTINCT user_id) AS count FROM "daily_statistics" WHERE "daily_statistics"."campaign_id" = $1 AND "daily_statistics"."metric" = 'participation' AND (properties -> 'assumed_gender' = 'female') [["campaign_id", 2]]
sql2[0]['count']
#=> 4

`new': invalid date ( ArgumentError)

Ok i somehow get this error for an function with an date:
C:/geburtstag/app/config/initializers/update_year.rb:11:in `new': invalid date (
ArgumentError)
from C:/geburtstag/app/config/initializers/update_year.rb:11:in `block i
n <top (required)>'
The code looks like this:
Patient.all.each do |f|
if (f.birthday.get_birthday + 1) != f.year
f.update_attribute :year, f.birthday.get_birthday + 1
end
if f.thisyear.blank?
f.update_attribute :thisyear, Date.new(Date.today.year, f.birthday.month, f.birthday.mday )
end
if f.thisyear.year != Date.today.year
f.update_attribute :thisyear, Date.new(Date.today.year, f.birthday.month,f.birthday.mday)
end
end
Line 11:
f.update_attribute :thisyear, Date.new(Date.today.year, f.birthday.month, f.birthday.mday )
I dont get why i get this error!! SO i made some test in the console, that all worked fine! I hope you can help me! Thanks
irb(main):005:0> c = Patient.find(24367)
←[1m←[36mPatient Load (0.0ms)←[0m ←[1mSELECT "patients".* FROM "patients" WHE
RE "patients"."id" = ? LIMIT 1←[0m [["id", 24367]]
=> #<Patient id: 24367, vorname: "Hanz", nachname: "Schnitzel", birthday: "1961-06
-29", geschlecht: "1", drucken: nil, extraanrede: nil, extratext: nil, year: nil
, rund: nil, thisyear: nil, zuletzt: nil, strasse: "Lsu 15", ort: "W÷rth", pl
z: "93386", created_at: "2013-09-19 16:37:28", updated_at: "2013-09-19 16:37:28"
>
irb(main):006:0> b = Patient.birthday
irb(main):007:0> d = c.birthday
=> Thu, 29 Jun 1961
irb(main):009:0> month = d.month
=> 6
irb(main):010:0> day = d.mday
=> 29
irb(main):011:0> year = Date.today.year
=> 2013
irb(main):012:0> neu = Date.new(year,month,day)
=> Sat, 29 Jun 2013
You are trying to instantiate a Date object with invalid parameters, e.g.
Date.new(2013,99,1)
# => ArgumentError: invalid date
You problem is most likely not the code presented above, but the data you are inserting. Check your database for records that have invalid dates.
You can prevent such errors by presenting an error to the user upon submission when the date is invalid. In order to acheive that, you could add a validation rule to your model e.g.
class Patient < ActiveRecord::Base
validate :birthday, if:->(d){ Date.valid_date?(d) }
end

Resources