psql excluding records base on another table - ruby-on-rails

i am using postgres and wishing to exclude users that are currently in one table from another. at present i am trying do this via the ActiveRecord system within Rails.
So i need it to get the ids from my Availability table, then return that id into my User table to remove them if they are in the Availability table.
#availabilities = Availability.where(:event_id => params[:id]).all
#players = User.where('team_id = ? and id <> ?', current_user[:team_id], #availabilities).all
this is returning the following error
PG::Error: ERROR: argument of WHERE must be type boolean, not type record
LINE 1: SELECT "users".* FROM "users" WHERE (team_id = 1 and id <> ...
^
: SELECT "users".* FROM "users" WHERE (team_id = 1 and id <> 101,102,103)
changed code as mentioned below, though the way i am doing it is still probably not ideal
#availabilities = Availability.where(:event_id => params[:id]).all
#exclude = Availability.where(:event_id => params[:id]).select(:user_id).pluck(:user_id)
if #exclude.count > 0
#players = User.where('team_id = ? and id NOT IN (?)', current_user[:team_id], #exclude).all
else
#players = User.where('team_id =?', current_user[:team_id])

You could do something like this:
#availabilities = Availability.where(event_id: params[:id]).pluck(:id)
#players = User.where(team_id: current_user[:team_id])
#players = #players.where('id NOT IN (?)', #availabilities) unless #availabilities.empty?
Using pluck() will return an array of IDs, then you can exclude them by using NOT IN (?)

Try:
id not in
The way pg engine sees it is ((team_id=1 and id <> 101), 102, 103). Thus the error you see.
Use it as:
User.where('team_id = ? and id not in (?)', current_user[:team_id], #availabilities).all

Related

Rails: How to access session parameter / ActiveRecord::StatementInvalid in Orders#create

I am working on a multistep form for an order placement section which uses a session session[:order_params] to store all form inputs before submit.
I need to be able to access a particular parameter (land) from the session in order to query for another resource (shippingservice) when navigating back in the form.
In my orders_controller.rb I have:
#shippingservices = #cart.available_shipping_services.joins(:lands).where(:lands => {:id => params[:id]})
but would need to specify the land.id from the session[:order_params].
When using session[:order_params] I get ActiveRecord::StatementInvalid in Orders#create:
Mysql::Error: Unknown column 'id.ship_to_last_name' in 'where clause': SELECT `shippingservices`.* FROM `shippingservices`
INNER JOIN `zones` ON `zones`.`id` = `shippingservices`.`zone_id`
INNER JOIN `lands_zones` ON `lands_zones`.`zone_id` = `zones`.`id`
INNER JOIN `lands` ON `lands`.`id` = `lands_zones`.`land_id`
WHERE `id`.`ship_to_last_name` = 'Smith'
AND `id`.`ship_to_address` = 'Somewherestreet'
AND `id`.`ship_to_city` = 'Nowheretown'
AND `id`.`ship_to_postal_code` = '99999'
AND `id`.`phone_number` = 'some number'
AND `id`.`shippingservice_id` = '34'
AND `id`.`email` = 'someone#example.tld'
AND `id`.`land_id` = '85'
AND `id`.`ship_to_first_name` = 'John'
AND (weightmin <= 200 AND weightmax >= 200 AND heightmin <= 12 AND heightmax >= 12 AND shippingservices.shippingcarrier = '1') AND (lengthmax >= 210 AND widthmax >= 149)
Since the correct land_id is present I am wondering how to provide only that value to the query.
Thank you in advance!
As per the description mentioned in the post, you want to access a particular key stored in session at a particular key.
Assuming order_params is a hash, you can get land_id using the below mentioned code:
session[:order_params][:land_id]
This will return the value of land_id and thus you can use it in the query.
To set session variable, you can set some data in a controller action
For eg:
app/controllers/sessions_controller.rb
def create
# ...
session[:current_user_id] = #user.id
# ...
end
And read it in another: app/controllers/users_controller.rb
def index
current_user = User.find_by_id(session[:current_user_id])
# ...
end

Ruby on Rails Query Result Group

In my controller I have
def services
#services = WorkQuote.group(:work_type_id).count
end
Which when ran in IRB:
irb(main):016:0> #services = WorkQuote.group(:work_type_id).count
(0.7ms) SELECT COUNT(*) AS count_all, work_type_id AS work_type_id FROM "work_quotes" GROUP BY "work_quotes"."work_type_id"
=> {1=>2, 3=>1}
Notice that the result is {1=>2, 3=>1}. In my controller I want to make a loop that builds a new array where the number to the left of the => is resolved by being inserted into this WorkType.find(number to the left of =>).worktype
So the new array would look like [Install=>2, Repair=>1} assuming that WorkType.find(1).worktype = Install and WorkType.find(3).worktype = Repair
Here is what worked for me although I am sure there is a cleaner way of doing this.
Basically grabbed each value with .each_key and pushed it into an array. Next I made a loop to grab the "count" which is the right side of each hash. Also in the loop I made an array that combined the resolved name of the WorkType id and the "count".
I realize that #printcount isn't needed in this situation.
#services = WorkQuote.group(:work_type_id).count
#printservices = []
#services.each_key {|key| #printservices.push(WorkType.find(key).worktype) }
#services = #services.to_a
#printcount = []
#printdisplay = []
iz = 0
while iz < #services.size
#printcount[iz] = #services[iz][1]
#printdisplay[iz] = [#printservices[iz], #services[iz][1]]
iz = iz + 1
end

Optimize code in RoR

I have this code:
def self.by_vibe(vibe_id)
self.joins(:vibes).where(vibes: {id: vibe_id})
end
This code repeats (with some differences) all over my model, for example:
def self.by_music(music_id)
self.joins(:musics).where(musics: {id: music_id})
end
I have four or five of these, and thought of making just one and came out with something like this (for reference, hash contains {:vibes=>2}):
def self.by(hash)
self.joins(hash.keys.first).where(hash.keys.first.to_s => id = hash.values.first)
end
My self.by_vibe makes this query:
SELECT "bcls".* FROM "bcls" INNER JOIN "bcls_vibes" ON "bcls_vibes"."bcl_id" = "bcls"."id" INNER JOIN "vibes" ON "vibes"."id" = "bcls_vibes"."vibe_id" WHERE "vibes"."id" = $1 [["id", 2]]
And my second approach makes this:
SELECT "bcls".* FROM "bcls" INNER JOIN "bcls_vibes" ON "bcls_vibes"."bcl_id" = "bcls"."id" INNER JOIN "vibes" ON "vibes"."id" = "bcls_vibes"."vibe_id" WHERE "bcls"."vibe_id" = 2
How can I fix that where clause? Notice that the first one (the correct one is WHERE "vibes"."id" = $1 [["id", 2]] and the wrong one is WHERE "bcls"."vibe_id" = 2. It's asking for a different table.
You can get the first value as well as the first key:
def self.by(hash)
self.joins(hash.keys.first).where(
{ hash.keys.first.to_s => { id: hash.values.first } }
)
end
If you're only accepting one key value pair in your hash though it might be better to have two arguments to by:
def self.by(assoc, obj_id)
self.joins(assoc).where(assoc => { id: obj_id })
end
I just found the proper way of doing what I was trying to do.
def self.by(hash)
self.joins(hash.keys.first).where(hash.keys.first.to_s => {id: hash.values.first})
end

rails gem will_paginate on top of custom method not working

In my controller, my filter_with_params() method is causing a syntax error in postgres when I try and stack will_paginate on top of it.
In my controller I call:
#styles = Style.filter_with_params(params).paginate(:page => params[:page], :per_page => 6)
Model method:
class Style < ActiveRecord::Base
def self.filter_with_params(params)
scoped = where("styles.item != ''")
if params[:t]
scoped = scoped.joins(:tags)
scoped = scoped.select("distinct styles.*, count(*) AS count")
scoped = scoped.where(tags: { name: params[:t] })
scoped = scoped.group('styles.id')
scoped = scoped.having("count(*) = #{params[:t].size}")
end
scoped
end
basically my filter method is looking for tags, and then i need to paginate on top of those results. Anyone with similar experience?
I'm using Rails 3 on this app
here is the postgres error
PG::Error: ERROR: syntax error at or near "distinct" LINE 1: SELECT COUNT(*) AS count_all, distinct styles.*, count(*) AS...
^
: SELECT COUNT(*) AS count_all, distinct styles.*, count(*) AS count, styles.id AS styles_id FROM "styles" INNER JOIN "tagizations" ON "tagizations"."style_id" = "styles"."id" INNER JOIN "tags" ON "tags"."id" = "tagizations"."tag_id" WHERE "tags"."name" IN ('engagement') AND (styles.polenza_item != '') GROUP BY styles.id HAVING count(*) = 1
Your SQL has a problem. You need to say distinct clause before the count ('count(*) as count_all'). That is, once you remove the first call to the count function, it should work.
SELECT distinct styles.*, count(*) AS count, styles.id AS styles_id FROM "styles" INNER JOIN "tagizations" ON "tagizations"."style_id" = "styles"."id" ...
You can test your query in your rails console:
>> sql = "SELECT distinct styles.*, count(*) AS count, styles.id AS styles_id..."
>> a = ActiveRecord::Base.connection.execute(sql)
>> a[0]
Hope this helps.

Rails Nested Query

I have follow query
notes = Note.where('notes.id IN
(
SELECT "notes"."id" FROM "notes"
WHERE "notes"."circle_id" = ?
)
OR notes.id IN
(
SELECT "notes"."id" FROM "notes"
INNER JOIN "circles_dreams"
ON "circles_dreams"."dream_id" = "notes"."dream_id"
WHERE "circles_dreams"."circle_id" = ?
)', #circle.id, #circle.id)
How to simplify this query?
Thanks.
First of all you can collect all needed notes id.
I supposed to think what you already have relations between Note and CirclesDream
note_ids = Note.where(circle_id: #circle.id).pluck(:id) # your first SELECT
dream_ids = CirclesDream.where(id: #circle.id).pluck(:note_id) # your second SELECT
notes_ids = note_ids | dreams_ids # combine them
notes = Note.where(id: notes_ids) # Now your
upd: I've just fixed typo. Changed id to note_id in second request
Try this
note_ids = Note.where('circle_id = ?', #circle.id).pluck(:id)
dream_note_ids = Note.joins(:circle_dreams).where('circle_dreams.circle_id = ?', #circle.id).plunk(:note_id)
notes_ids = note_ids | dream_note_ids
If your circle_dreams table can contain records having note_id = null, then you have to apply join. So i think this will work in your case....

Resources