active record quering in rails 4 and postgres - ruby-on-rails

I have 2 models
Class Ride
has_many :trips
#state (string: active or expired)
end
Class Trip
#date (Date attribute)
scope :active, -> (start_at = Date.today) { where("trips.date >= ?", [Date.today, start_at].max) }
end
Daily, I need update state on Rides with active state having all trips with date attribute < Date.today
how to perform this in 1 query?
i can archive such result using:
Ride.with_active_state.select{|r| r.trips.active.size ==0}
but it makes huje queries to count trips, eq:
[1] pry(main)> Ride.with_active_state.select{|r| r.trips.active.size ==0}
(7.3ms) SELECT f_geometry_column,coord_dimension,srid,type FROM geometry_columns WHERE f_table_name='rides'
Ride Load (1.6ms) SELECT "rides".* FROM "rides" WHERE (rides.workflow_state = 'active')
(2.9ms) SELECT f_geometry_column,coord_dimension,srid,type FROM geometry_columns WHERE f_table_name='trips'
(1.3ms) SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24') [["ride_id", 9]]
(0.7ms) SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24') [["ride_id", 10]]
(0.7ms) SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24') [["ride_id", 11]]
(0.7ms) SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24') [["ride_id", 12]]
(0.8ms) SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24') [["ride_id", 13]]
(0.8ms) SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24') [["ride_id", 14]]
(0.5ms) SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24') [["ride_id", 15]]
(0.5ms) SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24') [["ride_id", 16]]
(0.5ms) SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24') [["ride_id", 17]]
(0.5ms) SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24') [["ride_id", 18]]
(0.5ms) SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24') [["ride_id", 19]]
(0.5ms) SELECT COUNT(*) FROM "trips" WHERE "trips"."ride_id" = $1 AND (trips.date >= '2013-09-24') [["ride_id", 20]]
....

Add scopes on Ride with a group and having clause. It would check the count of all future trips of a ride and return the rides with 0 count.
Class Ride
scope :active_state, where(state: "active")
scope :with_nonactive_trips, -> (start_date = Date.today){ joins(:trips).
group("rides.id").
having( ["sum(trips.date > ?) = 0",start_date] ) }
end
Ride.active_state.with_nonactive_trips
# returns All the rides with state == active, alteast one trip and having no trips with date > Date.today
Using a lambda since you had it on the active scope in Trip. I am guessing you need to use a different date than Date.today for some queries.

Related

terminal output for Rails app produces double requests

My Rails app generates double requests with every page load, and I'm not able to diagnose the source of the problem. Answers here suggest removing all blank/self-referencing hrefs and running rake assets:clean - but neither has any impact.
Both of these requests are identical, save for timestamps and the as part of the controller action processing. The first request says Processing by TradesController#index as HTML whereas the second says Processing by TradesController#index as */*
Has anyone else dealt with this, and if so, how did you fix it?
Started GET "/swaps" for 2600:1700:ba01:ff10:cc31:d814:a204:d70e at 2020-02-23 14:32:25 -0800
Processing by TradesController#index as HTML
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
(0.4ms) SELECT COUNT(*) FROM "trades" WHERE "trades"."trade_requester_id" = $1 AND "trades"."approved_at" IS NULL [["trade_requester_id", 1]]
(0.3ms) SELECT COUNT(*) FROM "trades" WHERE "trades"."trade_recipient_id" = $1 AND "trades"."approved_at" IS NULL [["trade_recipient_id", 1]]
Rendering trades/index.html.erb within layouts/application
Rendered trades/_trades_menu.html.erb (0.5ms)
CACHE (0.0ms) SELECT COUNT(*) FROM "trades" WHERE "trades"."trade_recipient_id" = $1 AND "trades"."approved_at" IS NULL [["trade_recipient_id", 1]]
Rendered trades/index.html.erb within layouts/application (3.0ms)
CACHE (0.0ms) SELECT COUNT(*) FROM "trades" WHERE "trades"."trade_recipient_id" = $1 AND "trades"."approved_at" IS NULL [["trade_recipient_id", 1]]
Transaction Load (0.5ms) SELECT "transactions".* FROM "transactions" WHERE "transactions"."recipient_id" = $1 AND "transactions"."archived_by_recipient" = $2 [["recipient_id", 1], ["archived_by_recipient", false]]
Transaction Load (0.5ms) SELECT "transactions".* FROM "transactions" WHERE "transactions"."sender_id" = $1 AND (state = 'approved' OR state = 'force_flipped' OR state = 'payment_sent' OR state = 'payment_declined' OR state = 'passed' OR state = 'paid' OR state = 'refunded' OR state = 'shipped' OR state = 'received' OR state = 'not_received' OR state = 'unpaid' OR state = 'ignored' OR state = 'declined') AND "transactions"."archived_by_sender" = $2 [["sender_id", 1], ["archived_by_sender", false]]
PaymentTransfer Load (0.3ms) SELECT "payment_transfers".* FROM "payment_transfers" WHERE "payment_transfers"."user_id" = $1 AND (user_id = 1 AND read = FALSE) [["user_id", 1]]
CACHE Transaction Load (0.0ms) SELECT "transactions".* FROM "transactions" WHERE "transactions"."recipient_id" = $1 AND "transactions"."archived_by_recipient" = $2 [["recipient_id", 1], ["archived_by_recipient", false]]
CACHE Transaction Load (0.0ms) SELECT "transactions".* FROM "transactions" WHERE "transactions"."sender_id" = $1 AND (state = 'approved' OR state = 'force_flipped' OR state = 'payment_sent' OR state = 'payment_declined' OR state = 'passed' OR state = 'paid' OR state = 'refunded' OR state = 'shipped' OR state = 'received' OR state = 'not_received' OR state = 'unpaid' OR state = 'ignored' OR state = 'declined') AND "transactions"."archived_by_sender" = $2 [["sender_id", 1], ["archived_by_sender", false]]
CACHE PaymentTransfer Load (0.0ms) SELECT "payment_transfers".* FROM "payment_transfers" WHERE "payment_transfers"."user_id" = $1 AND (user_id = 1 AND read = FALSE) [["user_id", 1]]
(1.2ms) SELECT COUNT(*) FROM "conversations" INNER JOIN "messages" ON "messages"."conversation_id" = "conversations"."id" INNER JOIN "users" ON "users"."id" = "messages"."user_id" WHERE ((conversations.sender_id = 1 OR conversations.receiver_id = 1)) AND (messages.user_id != 1 AND read = FALSE)
Rendered layouts/_header.html.erb (9.2ms)
Completed 200 OK in 58ms (Views: 48.5ms | ActiveRecord: 4.2ms)
(0.2ms) BEGIN
(0.2ms) COMMIT
Started GET "/swaps" for 2600:1700:ba01:ff10:cc31:d814:a204:d70e at 2020-02-23 14:32:26 -0800
Processing by TradesController#index as */*
User Load (0.5ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2 [["id", 1], ["LIMIT", 1]]
(0.4ms) SELECT COUNT(*) FROM "trades" WHERE "trades"."trade_requester_id" = $1 AND "trades"."approved_at" IS NULL [["trade_requester_id", 1]]
(0.4ms) SELECT COUNT(*) FROM "trades" WHERE "trades"."trade_recipient_id" = $1 AND "trades"."approved_at" IS NULL [["trade_recipient_id", 1]]
Rendering trades/index.html.erb within layouts/application
Rendered trades/_trades_menu.html.erb (0.6ms)
CACHE (0.0ms) SELECT COUNT(*) FROM "trades" WHERE "trades"."trade_recipient_id" = $1 AND "trades"."approved_at" IS NULL [["trade_recipient_id", 1]]
Rendered trades/index.html.erb within layouts/application (27.1ms)
CACHE (0.0ms) SELECT COUNT(*) FROM "trades" WHERE "trades"."trade_recipient_id" = $1 AND "trades"."approved_at" IS NULL [["trade_recipient_id", 1]]
Transaction Load (0.5ms) SELECT "transactions".* FROM "transactions" WHERE "transactions"."recipient_id" = $1 AND "transactions"."archived_by_recipient" = $2 [["recipient_id", 1], ["archived_by_recipient", false]]
Transaction Load (0.6ms) SELECT "transactions".* FROM "transactions" WHERE "transactions"."sender_id" = $1 AND (state = 'approved' OR state = 'force_flipped' OR state = 'payment_sent' OR state = 'payment_declined' OR state = 'passed' OR state = 'paid' OR state = 'refunded' OR state = 'shipped' OR state = 'received' OR state = 'not_received' OR state = 'unpaid' OR state = 'ignored' OR state = 'declined') AND "transactions"."archived_by_sender" = $2 [["sender_id", 1], ["archived_by_sender", false]]
PaymentTransfer Load (0.3ms) SELECT "payment_transfers".* FROM "payment_transfers" WHERE "payment_transfers"."user_id" = $1 AND (user_id = 1 AND read = FALSE) [["user_id", 1]]
CACHE Transaction Load (0.0ms) SELECT "transactions".* FROM "transactions" WHERE "transactions"."recipient_id" = $1 AND "transactions"."archived_by_recipient" = $2 [["recipient_id", 1], ["archived_by_recipient", false]]
CACHE Transaction Load (0.0ms) SELECT "transactions".* FROM "transactions" WHERE "transactions"."sender_id" = $1 AND (state = 'approved' OR state = 'force_flipped' OR state = 'payment_sent' OR state = 'payment_declined' OR state = 'passed' OR state = 'paid' OR state = 'refunded' OR state = 'shipped' OR state = 'received' OR state = 'not_received' OR state = 'unpaid' OR state = 'ignored' OR state = 'declined') AND "transactions"."archived_by_sender" = $2 [["sender_id", 1], ["archived_by_sender", false]]
CACHE PaymentTransfer Load (0.0ms) SELECT "payment_transfers".* FROM "payment_transfers" WHERE "payment_transfers"."user_id" = $1 AND (user_id = 1 AND read = FALSE) [["user_id", 1]]
(0.7ms) SELECT COUNT(*) FROM "conversations" INNER JOIN "messages" ON "messages"."conversation_id" = "conversations"."id" INNER JOIN "users" ON "users"."id" = "messages"."user_id" WHERE ((conversations.sender_id = 1 OR conversations.receiver_id = 1)) AND (messages.user_id != 1 AND read = FALSE)
Rendered layouts/_header.html.erb (8.7ms)
Completed 200 OK in 152ms (Views: 116.6ms | ActiveRecord: 4.1ms)
(0.1ms) BEGIN
(0.1ms) COMMIT

Eagerload objects with has_many has_many association ANd where not all associations exist

I have 2 models: Deal and User with a many_to_many relations and a user_deal joined table.
On the homepage i display a list of Deals. For each Deal I use inside the view n attribute that is inside the user_deal table.
How can I eager load this ?
I tried to do this:
homepage controller
def home
#deals = Deal.includes(:user_deals)
respond_to do |format|
format.html # home.html.erb
format.json { render json: #deals }
format.xml { render xml: #deals }
# format.atom
end
end
end
Models
class Deal < ActiveRecord::Base
has_many :user_deals, dependent: :destroy
has_many :users, through: :user_deals
end
class User < ActiveRecord::Base
has_many :user_deals
has_many :deals, through: :user_deals
end
class UserDeal < ActiveRecord::Base
belongs_to :user, :foreign_key => 'user_id'
belongs_to :deal, :foreign_key => 'deal_id'
end
But I feel it's not working as it's preloading things but then loading each object a second time...
Processing by StaticPagesController#home as HTML
(0.5ms) SELECT COUNT(*) FROM "Deals" AND "Deals"."featured" = 't'
Deal Load (0.7ms)
SELECT "Deals".* FROM "Deals" WHERE "Deals"."country" = $1 AND "Deals"."featured" = 't' ORDER BY "Deals"."Deal_end_date" ASC
// it seems here below to implement the preloading
UserDeal Load (1.2ms) SELECT "user_deals".* FROM "user_Deals" WHERE "user_Deals"."Deal_id" IN (30, 339, 341, 337, 353, 31, 354, 260)
//but then it's loading things individually again
UserDeal Load (0.6ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 30) LIMIT 1
UserDeal Load (0.6ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 339) LIMIT 1
UserDeal Load (0.7ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 341) LIMIT 1
UserDeal Load (0.7ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 337) LIMIT 1
UserDeal Load (0.6ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 353) LIMIT 1
UserDeal Load (0.7ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 31) LIMIT 1
UserDeal Load (0.9ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 354) LIMIT 1
UserDeal Load (0.6ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 260) LIMIT 1
My assumption of where the problem comes from (I'm not sure)
The problem might be inside the User_deal table. It works this way: if a user participated in a deal, a new line is created with user_id = 5, deal_id= 4, number_of_participations = 6
So if the user 4 never participated in a deal 7, there is no line user_id= 4 and deal_id = 7
So on the homepage, Rails go to fetch the list of deals: deal 1, deal 2...and deal 7.
But he does not find the line where deal_7 as there is no such line.
Ideally, I should tell Rails to includes(:user_deals) but only those where inside the joined table UserDeals where user_id= current_user.id OR where the line with user_id = current_user.id does NOT exist...which I did not manager to implement anyway
but I'm a RoR rookie so I'm not sure of my ideas here above
EDIT
Following suggestion to try eager_load instead of includes, I get:
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT 1 [["id", 625]]
Processing by StaticPagesController#home as HTML
(0.7ms) SELECT COUNT(DISTINCT "deals"."id") FROM "deals" LEFT OUTER JOIN "user_deals" ON "user_deals"."deal_id" = "deals"."id" WHERE "deals"."country" = $1 AND (deal_launch_date <= '2016-05-02 17:21:59.547029' AND deal_end_date >= '2016-05-02 17:21:59.547087') AND "deals"."featured" = 't' [["country", "France"]]
SQL (3.0ms) SELECT "deals"."id" AS t0_r0, "deals"."country" AS t0_r1, "deals"."title" AS t0_r2, "deals"."deal_card_edito" AS t0_r3, "deals"."twitter_msg" AS t0_r4, "deals"."image_url" AS t0_r5, "deals"."prelaunch_date" AS t0_r6, "deals"."featured" AS t0_r9, "deals"."admin_user_id" AS t0_r10, "deals"."created_at" AS t0_r11, "deals"."updated_at" AS t0_r12,........................................................................................................
"user_deals"."id" AS t1_r0, "user_deals"."user_id" AS t1_r1, "user_deals"."deal_id" AS t1_r2, "user_deals"."number_participations" AS t1_r3, "user_deals"."nb_new_clicks" AS t1_r4, "user_deals"."created_at" AS t1_r5, "user_deals"."updated_at" AS t1_r6 FROM "deals" LEFT OUTER JOIN "user_deals" ON "user_deals"."deal_id" = "deals"."id" WHERE "deals"."country" = $1 AND (deal_launch_date <= '2016-05-02 17:21:59.547029' AND deal_end_date >= '2016-05-02 17:21:59.547087') AND "deals"."featured" = 't' ORDER BY "deals"."deal_end_date" ASC [["country", "France"]]
UserDeal Load (0.9ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 30) LIMIT 1
UserDeal Load (1.0ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 339) LIMIT 1
UserDeal Load (0.6ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 341) LIMIT 1
UserDeal Load (0.6ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 337) LIMIT 1
UserDeal Load (0.9ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 353) LIMIT 1
UserDeal Load (1.0ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 31) LIMIT 1
UserDeal Load (0.5ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 354) LIMIT 1
UserDeal Load (0.9ms) SELECT "user_deals".* FROM "user_deals" WHERE (user_id = 625 AND deal_id = 260) LIMIT 1

How to fetch records from last 7 days with padding to 0 if no records found?

I'm trying to fetch records from the last 7 days (may change to support month and year) to populate a chart, and I need to pad the days where no records where found to 0. I first tried grouping but found no way of padding the data, so I came up with this:
today = Date.today
array_data = (today - 6.days..today).map do |day|
total_time = #project.time_entries.where(created_at: (day.beginning_of_day..day.end_of_day)).map(&:duration_hours).sum
{ day.strftime("%a %d %b") => total_time }
end
#entries_data = array_data.reduce Hash.new, :merge
The result is a hash with a day as a key and the sum of a calculated property as the value.
This however, requires a database query for each day:
TimeEntry Load (1.1ms) SELECT "time_entries".* FROM "time_entries" WHERE "time_entries"."project_id" IN ('bd9f541c-e37a-45de-bc94-28bef2b5eade')
TimeEntry Load (0.4ms) SELECT "time_entries".* FROM "time_entries" WHERE "time_entries"."project_id" = $1 AND ("time_entries"."created_at" BETWEEN '2016-03-21 04:30:00.000000' AND '2016-03-22 04:29:59.999999') [["project_id", "bd9f541c-e37a-45de-bc94-28bef2b5eade"]]
TimeEntry Load (0.2ms) SELECT "time_entries".* FROM "time_entries" WHERE "time_entries"."project_id" = $1 AND ("time_entries"."created_at" BETWEEN '2016-03-22 04:30:00.000000' AND '2016-03-23 04:29:59.999999') [["project_id", "bd9f541c-e37a-45de-bc94-28bef2b5eade"]]
TimeEntry Load (0.2ms) SELECT "time_entries".* FROM "time_entries" WHERE "time_entries"."project_id" = $1 AND ("time_entries"."created_at" BETWEEN '2016-03-23 04:30:00.000000' AND '2016-03-24 04:29:59.999999') [["project_id", "bd9f541c-e37a-45de-bc94-28bef2b5eade"]]
TimeEntry Load (0.2ms) SELECT "time_entries".* FROM "time_entries" WHERE "time_entries"."project_id" = $1 AND ("time_entries"."created_at" BETWEEN '2016-03-24 04:30:00.000000' AND '2016-03-25 04:29:59.999999') [["project_id", "bd9f541c-e37a-45de-bc94-28bef2b5eade"]]
TimeEntry Load (0.5ms) SELECT "time_entries".* FROM "time_entries" WHERE "time_entries"."project_id" = $1 AND ("time_entries"."created_at" BETWEEN '2016-03-25 04:30:00.000000' AND '2016-03-26 04:29:59.999999') [["project_id", "bd9f541c-e37a-45de-bc94-28bef2b5eade"]]
TimeEntry Load (0.6ms) SELECT "time_entries".* FROM "time_entries" WHERE "time_entries"."project_id" = $1 AND ("time_entries"."created_at" BETWEEN '2016-03-26 04:30:00.000000' AND '2016-03-27 04:29:59.999999') [["project_id", "bd9f541c-e37a-45de-bc94-28bef2b5eade"]]
TimeEntry Load (0.5ms) SELECT "time_entries".* FROM "time_entries" WHERE "time_entries"."project_id" = $1 AND ("time_entries"."created_at" BETWEEN '2016-03-27 04:30:00.000000' AND '2016-03-28 04:29:59.999999') [["project_id", "bd9f541c-e37a-45de-bc94-28bef2b5eade"]]
How can I rework this to make it send only 1 query to the database?
Not certain this is what you mean, but here's what I think you need to do:
Run the query getting all data for the last N days.
Group these records by the day
Merge this on top of a hash with values of { date => 0} for each of the last N days
Ok, as tpbowden mentioned in his answer, I managed to reduce it to 1 query like this:
date_format = "%d %b"
entries_last_week = time_entries.group_by { |t| t.created_at.to_date.strftime(date_format) }.map { |k, v| { k => v.map(&:duration_hours).sum } }
entries_hash = entries_last_week.reduce Hash.new, :merge
today = Date.today
days = (today - 6.days..today).map { |day| { day.strftime(date_format) => 0 } }
hash_of_days = days.reduce Hash.new, :merge
hash_of_days.merge(entries_hash)

Rails 4 how to include polymorphic

I have a Webcam model which has many Urls
class Webcam < ActiveRecord::Base
has_many :urls, -> { where('kind LIKE ?','preview_url')}, :as => :urlable, :dependent => :destroy
has_one :preview_url, -> { where('kind LIKE ?', 'preview_url') }, :as => :urlable, :dependent => :destroy, :class_name => 'Url'
end
class Url < ActiveRecord::Base
belongs_to :urlable, polymorphic: true
end
So Webcam.joins(:preview_url).where(:id=>cam_ids) does work, but I still have a sql call for each cam.
Url Load (0.2ms) SELECT "urls".* FROM "urls" WHERE "urls"."urlable_id" = $1 AND "urls"."urlable_type" = $2 AND (kind LIKE 'preview_url') AND "urls"."kind" = $3 ORDER BY "urls"."id" ASC LIMIT 1 [["urlable_id", 9756], ["urlable_type", "Webcam"], ["kind", "preview_url"]]
CACHE (0.0ms) SELECT "urls".* FROM "urls" WHERE "urls"."urlable_id" = $1 AND "urls"."urlable_type" = $2 AND (kind LIKE 'preview_url') AND "urls"."kind" = $3 ORDER BY "urls"."id" ASC LIMIT 1 [["urlable_id", 9756], ["urlable_type", "Webcam"], ["kind", :preview_url]]
Url Load (0.2ms) SELECT "urls".* FROM "urls" WHERE "urls"."urlable_id" = $1 AND "urls"."urlable_type" = $2 AND (kind LIKE 'preview_url') AND "urls"."kind" = $3 ORDER BY "urls"."id" ASC LIMIT 1 [["urlable_id", 9759], ["urlable_type", "Webcam"], ["kind", "preview_url"]]
CACHE (0.0ms) SELECT "urls".* FROM "urls" WHERE "urls"."urlable_id" = $1 AND "urls"."urlable_type" = $2 AND (kind LIKE 'preview_url') AND "urls"."kind" = $3 ORDER BY "urls"."id" ASC LIMIT 1 [["urlable_id", 9759], ["urlable_type", "Webcam"], ["kind", :preview_url]]
Url Load (0.2ms) SELECT "urls".* FROM "urls" WHERE "urls"."urlable_id" = $1 AND "urls"."urlable_type" = $2 AND (kind LIKE 'preview_url') AND "urls"."kind" = $3 ORDER BY "urls"."id" ASC LIMIT 1 [["urlable_id", 9760], ["urlable_type", "Webcam"], ["kind", "preview_url"]]
CACHE (0.0ms) SELECT "urls".* FROM "urls" WHERE "urls"."urlable_id" = $1 AND "urls"."urlable_type" = $2 AND (kind LIKE 'preview_url') AND "urls"."kind" = $3 ORDER BY "urls"."id" ASC LIMIT 1 [["urlable_id", 9760], ["urlable_type", "Webcam"], ["kind", :preview_url]]
How can I avoid these many sql calls?
You should use .includes(:urls, :preview_url) (not .joins) to avoid N+1 queries problem (see Rails Guides on the topic).
You should also have a separate urls.kind value for preview_url because you can't distinguish it from other urls now.

order active_admin column by parent item in belongs_to relationship

I have two models: show_request and show. A show_Request belongs_to a show and a show has_many show_requests. On the show_request page in active_admin, I want to order show_requests by the show's created_at value. Here is my code so far:
ActiveAdmin.register ShowRequest do
controller do
def scoped_collection
end_of_association_chain.includes(:show)
#I also tried ShowRequest.includes(:show)
end
end
index do
column 'Show', sortable: "shows.created_at_asc" do |show_req|
link_to show_req.show.name, admin_show_path(show_req.show)
end
end
end
Here are the server logs:
Started GET "/admin/show_requests" for 127.0.0.1 at 2015-09-18 09:35:36 -0400
Processing by Admin::ShowRequestsController#index as HTML
AdminUser Load (0.3ms) SELECT "admin_users".* FROM "admin_users" WHERE "admin_users"."id" = 1 ORDER BY "admin_users"."id" ASC LIMIT 1
(1.2ms) SELECT COUNT(*) FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't')
(0.2ms) SELECT COUNT(*) FROM "show_requests"
(0.2ms) SELECT COUNT(*) FROM "show_requests" WHERE (not_going_to_show = 't' AND i_want_my_horse_to_compete = 'f')
(0.3ms) SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't') LIMIT 30 OFFSET 0) subquery_for_count
CACHE (0.0ms) SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't') LIMIT 30 OFFSET 0) subquery_for_count
CACHE (0.0ms) SELECT COUNT(*) FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't')
CACHE (0.0ms) SELECT COUNT(count_column) FROM (SELECT 1 AS count_column FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't') LIMIT 30 OFFSET 0) subquery_for_count
ShowRequest Load (2.0ms) SELECT "show_requests".* FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't') ORDER BY "show_requests"."id" desc LIMIT 30 OFFSET 0
Show Load (9.7ms) SELECT "shows".* FROM "shows" WHERE "shows"."id" IN (2, 1)
User Load (0.4ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 2]]
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
CACHE (0.0ms) SELECT "users".* FROM "users" WHERE "users"."id" = $1 LIMIT 1 [["id", 1]]
Show Load (0.2ms) SELECT "shows".* FROM "shows"
User Load (0.2ms) SELECT "users".* FROM "users"
This is not working. It is not affecting the order of the columns at all. How do I fix this?
Take a look at this part of the log:
ShowRequest Load (2.0ms) SELECT "show_requests".* FROM "show_requests" WHERE (not_going_to_show = 'f' OR i_want_my_horse_to_compete = 't') ORDER BY "show_requests"."id" desc LIMIT 30 OFFSET 0
Show Load (9.7ms) SELECT "shows".* FROM "shows" WHERE "shows"."id" IN (2, 1)
You can see that the ShowRequests and Shows are loaded in separate queries. sortable is not going to work here, because you can't order one table by a field of another without a join. The fix should be to tell ActiveRecord that you need to reference the shows table in your query:
controller do
def scoped_collection
super.includes(:show).references(:shows)
end
end
index do
column :show, sortable: 'shows.created_at'
end
references only works with includes, and forces Rails to perform a join when eager loading.

Resources