SQL Rails rescue request for non existing user - sql

I have small problem. Lets say I have users 1, 2 and 4. And now I'm trying to use this query:
User.select(:channel).where(:id => rand(1..User.count)).first.channel
Which in this case works like this:
User.select(:channel).where(:id => rand(1..3)).first.channel
And well, thats my problem. I can select user 1 and user 2. User 4 is unreachable. And if it try to take user 3 it returns me that there is no .channel method, because everything is nil then... What should I do so it could reach users 1, 2, 4 and ignore user 3 which is nil?

You could first get the list of available record IDs and then pick a random id:
ids = User.pluck(:id)
User.select(:channel).where(:id => ids.sample).first.channel
But of course that requires two queries so if that isn't efficient enough you could try telling the DB itself to select a random record. For example, if you're using MySQL you could so something like this:
User.order('rand()').limit(1)

Related

Sorting out data from SQL in Rails

So I'm trying to get some specific data out of my database but I've searching online and can't find how to do this (probably because I'm searching for the wrong terms).
I start with getting all the participants with a specific id like this :
contributions = Participant.where(user_id: params[:id])
This will give me a json result like this :
0: {id_request: "1", user_id: "titivermeesch#gmail.com"}
1: {id_request: "2", user_id: "titivermeesch#gmail.com"}
So here I have all the requests (there is a Request class) that have that specific user_id.
Now I want to do this :
all = Request.where(id: id_request)
This obviously don't work but how would I get all those requests that have all those id's that come from the first database query?
So with the results above I should get Request 1 and 2, but how? Can anyone guide me?
How about
contributions = Participant.where(user_id: params[:id])
# Assuming the above is an active record query and id_request is a property of Participant
all = Request.where(id: contributions.map(&:id_request))
This is the equivalent of the SQL
select * from requests where id in (array_of_request_ids)
If You added associations in your model? it's very easy to retrieve the records
This should work:
Request.joins(:participants).where("participants.user_id = ?", params[:id])
Also you might want to read the following part (on joins)

Rails joins query killed or just too slow. Please recommend the proper way to create queries

I am having trouble properly creating query with joins. It starts to talk to server but it ends up clogged and saying "killed" (in Rails console)
I have to models.
One is 'User', the other one is 'Availability'
Some users will open availabilities in 2 weeks. And I'd like to fetch 50 users with this condition with page variable.(because there will be many of them and I'd like to fetch 50 on every call)
Availability has two columns: user_id and start_time(datetime)
And the association is that user has many availabilities.
The query looks like the below.
people = User
.where(role: SOMETHING)
.includes(:availabilities)
.joins(:availabilities)
.where('availabilities.start_time > ?', Time.now)
.where('availabilities.start_time < ?', Time.now + 2.weeks)
.limit(5)
.offset(50 * (n-1))
where n is integer from 1
However, this query never gives me result on the production (in the console it's killed. Before the console kills the process, when querying, it shows normal query statement (sql 30ms for instance) forever. In local, where data is small, it works. Are there anything missing here?
Please give me any advice!!
And weird thing is ,
people = User
.where(role: SOMETHING)
.includes(:availabilities)
.joins(:availabilities)
.limit(5)
.offset(50 * (n-1))
then if
people.map(&:id) => [18,18,18,18,18]
which means people is inappropriately fetched. I am just confused here..!
Includes availabilities will generate availability model instances after querying.
If availability rows are so many, it will cost a lot of time.
If you won't use availabilities after querying, please try
people = User
.where(role: ROLES)
.joins(:availabilities)
.where(availabilities: {start_time: (Time.now)..(2.weeks.from_now)})
.offset(50 * (n-1))
.limit(5)
I kind of find the way to work it:
people = User
.where(role: ROLES)
.joins(:availabilities)
.where(availabilities: { start_time: (Time.now)..(2.weeks.from_now) })
.distinct
.offset(50 * (n-1))
.limit(5)
Then:
people.map(&:id), => [x,y,z,l,m]

Rails - Check if item is in the last 15 entries of database

I'm new to Rails and SQL and having issues about this particular problem...
I have a database 'Item' containing 'items' added by users, with three columns:
- one is a string with the name ':name' of the item
- one is a foreign key for the category of the item ':category_id'
- the last is a string containing the IP adress of the user ':ip' who added the item.
(There is also a timestamp).
I would like to check if the IP of the current user is somewhere in the last 15 entries of database for the current category.
I've been struggling with the right selector in the item controller, to select the value of the "IP" column for the last 15 entries for the correct category_id. An example of what I tried :
#last_fifteen_ip = Item.select("ip").last(15).where(category_id: params[:id])
user_ip = request.remote_ip
if #last_fifteen_ip.include?(user_ip)
flash[:success] = "User is in the last 15 IP"
end
Doesn't work at all... maybe because #last_fifteen_ip doesn't select only the IPs so I can't use .include? correctly...
Thank you very much if you can help me.
Doesn't look like your #last_fifteen_ip is returning an array of IPs, which is what you want.
Try this:
#last_fifteen_ip = Item.where(category_id: params[:id]).pluck(:ip).last(15)
This should return an array of IPs. That would make your .include? query work.

Easiest way to find a value in one of three columns?

I am using twilio to provide audio conference functionality in my rails app. When I call my conference number, twilio passes on a couple of values - including 'From' which contains the caller's phone number in international format.
I have a profile for every user in my system and in my controller I am querying the profile to provide a personalised welcome message. Every profile contains between 0 and 3 numbers (primary, secondary and cellphone) and I need to check the caller's ID against those three fields in all profiles.
When I use the console on my dev machine, the following code finds the correct profile:
Profile.find_by('+44000000000')
When I upload to heroku, I use following code instead:
name = Profile.find_by(params['From']) || 'there'
Which causes an error in my app:
2014-04-03T19:20:22.801284+00:00 app[web.1]: PG::DatatypeMismatch: ERROR: argument of WHERE must be type boolean, not type bigint
2014-04-03T19:20:22.801284+00:00 app[web.1]: LINE 1: SELECT "profiles".* FROM "profiles" WHERE (+4400000000) ...
Any suggestion how that could be solved?
Thanks!
Additional information:
I think my problem is that I don't know how to query either the whole profile or three columns at once. Right now the code:
name = Profile.find_by(params['From'])
is not correct (params['From'] contains a phone number) because I am not telling rails to query the columns primary phone number, secondary phone number and cellphone. Neither am I querying the whole profile which would also be an option.
So the question basically is:
How can I change this code:
Profile.find_by(params['From'])
so that it queries either all fields in all profiles or just the three columns with phone numbers which each profile contains?
Is there something like Profile.where(:primary_number).or.where(:secondary_number)or.where(:cellphone) => params['From']
?
I am not familiar with twilio and not sure if this helps but find and find_by_attribute_name accepts array of values as options:
name = Profile.find_by([params['From'], 'there'] )
suppose params['From'] was here , This should generate:
SELECT `profiles`.* FROM `profiles` WHERE `profiles`.`attribute` IN ('here', 'there')
Or:
If you are trying to build dynamic matcher at run time , which is called Meta-programming , you can try this code:
name = eval("Profile.find_by_#{params['From']) || 'there'}(#rest of query params here) ")
Update
First of all, i think you are not using find_by correctly!! the correct syntax is:
Model.find_by(attribute_name: value)
#e.g
Profile.find_by(phone_number: '0123456')
Which will call where and retrive one record, but passing a value will generate a condition that always passes, for example:
Model.find_by('wrong_condition')
#will generate SQL like:
SELECT `models`.* FROM `models` WHERE ('wrong_condition') LIMIT 1
#which will return the first record in the model since there is no valid condition here
Why don't you try:
Profile.where('primary_number = ? OR secondary_number = ? OR cellphone = ?', params['From'], params['From'], params['From'])
You can write your query like:
Profile.where("primary_number = ? or secondary_number = ? or cellphone = ?", params['From'])
Just double check the syntax, but that should do it.

How to access data of query Comment.group('user').count

The query below in Rails console:
i = Comment.group('user_id').count
gives me output like this:
{1=>3, 2=>6, 3=>2, 4=>8}
where 1,2,3,4 are user ids and 3,6,2,8 are the count of the rows with these user ids. Please shed some light on me on how I can use these data. As i.count gives me total no.
I want to access these individual user row counts. Again, i[0].count or i[1].count gives me an error.
The expression gives you a Ruby Hash of key/value pairs, which you can access using the following:
i[1] # => 3
i[2] # => 6
... etc ...
You don't need to call count on them, the value of calling i[2] will be the count.
If I understand your question, you can access the hash with i[1] to get the comment count for the user with ID #1, instead of adding .count as you did in your example.