Searching from a range of ids in ActiveRecord - ruby-on-rails

How can I do something like this in range?
User.find(14000..14500)
I need to choose a certain range of Users starting and finishing on specifics ids.

You can use the where method:
User.where(id: 14000..14500)
Explanation
The where method here receives a hash argument in its shortened form, where the value for the id key is a Range.

You can do it like this too:
User.find_by_id(14000..14500)

Try this also
User.find((start..end).to_a)
Ex -
User.find((14000..14500).to_a)

You can use range definition for scoped:
User.find(1) # returns the object for ID = 1
User.find([1])
User.find(1, 2, 9) # returns an array for objects with IDs in (1, 2, 9)
User.find([1, 2, 9])
User.scoped(:conditions => { :id => 1..9})

Related

How can .where accept an array without braces?

I'm not sure how is this implemented, when you do something like:
Model.where(["subjects = ?", 1])
Rails allows you to omit the braces:
Model.where("subjects = ?", 1)
I know this is possible with hashes, but how is it possible so you can pass ANY number of arguments (you can have 100 question marks if you want) and for Rails to still interpret this as an array?
In Ruby a method can accept splat arguments.
def foo(*a)
a
end
foo('bar', 'baz')
# => ["bar", "baz"]
The splat gathers up any remaining arguments. You can even use it with regular arguments:
def foo(a, *b)
b
end
foo('bar', 'baz')
# => ["baz"]
You can even do something like:
def foo(*a)
a.length == 1 && a.first.is_a?(Array) ? a.first : a
end
Now calling foo('bar', 'baz') and foo(['bar', 'baz']) have the same return value.
However if what you want is a WHERE condition where the value can be one of many possible values you would write it like so:
Model.where(foo: [1, 2, 3, 5])
Which would create a WHERE models.foo IN (1,2,3,5) clause.
From the Docs
Model.where(array)
If an array is passed, then the first element of the array is treated as a template, and the remaining elements are inserted into the template to generate the condition. Active Record takes care of building the query to avoid injection attacks, and will convert from the ruby type to the database type where needed. Elements are inserted into the string in the order in which they appear.
User.where(["name = ? and email = ?", "Joe", "joe#example.com"])
# SELECT * FROM users WHERE name = 'Joe' AND email = 'joe#example.com';

Rails: why does activerecord find and find_by_attribute don't behave the same?

I love activerecords multiple find:
Country.find(1, 2) # Returns an array of countries
I love auto find_by_attribute generated:
Country.find_by_iso2('US') # Equivalent to Country.where(iso2: 'US').first
So why the combination doesn't work/exists?
Country.find_by_iso2('US', 'CA')
# Would expect an array, it fails because too many arguments
Country.find_by_iso2(['US', 'CA'])
# Would expect an array, returns only the last one (Canada)
Instead I sadly have to write:
['US', 'CA'].map{ |e| Country.find_by_iso2(e) }
which is much less elegant.
Model.find_by(*args)
Finds the first record matching the specified conditions. There is no implied ordering so if order matters, you should specify it yourself.
If no record is found, returns nil.
Post.find_by name: 'Spartacus', rating: 4
Post.find_by "published_at < ?", 2.weeks.ago
docs: http://apidock.com/rails/v4.0.2/ActiveRecord/FinderMethods/find_by
File activerecord/lib/active_record/relation/finder_methods.rb, line 47
def find_by(*args)
where(*args).take
end
Beacuse it accepts an arguments as array and return only first element of it

how to extract multiple integer from string in rails

I have the following in my url. I need to extract both 4 and 2 separately for the purpose of searching. These two integer, one is category id and other is sub category id
params[:id].scan(/\d+$/).first
using the above scan i can get 4 but how can i get more than one integers
my-url-for-test-4-2
I have created a helper method
def string_to_int(param,key)
param.scan(/\d+/).map(&:to_i).key
end
And i tried it from my controller like this
id = string_to_int(params[:id],'first')
But getting error as
undefined method `key' for [4, 2]:Array
Why it is not acception.
Answer lies in your question
params[:id].scan(/\d/) will result in array.
params[:id].scan(/\d+/).map(&:to_i)
If you are passing first or last as key :
def string_to_int(param,key)
param[:id].scan(/\d+/).map(&:to_i).send(key)
end
You can match against the last two numerical parts (separated by hyphens) in your :id parameter:
string = params[:id].to_s
ids = string.scan(/-(\d+)-(\d+)$/)[0] # .try(:map, &:to_i)
Update:
Here's a not-too-edge case that would be handled well:
a = "random1-2string-3-4-5"
a.scan(/-(\d+)-(\d+)$/) # => [["4", "5"]]
a.scan(/-(\d+)-(\d+)$/)[0] # => ["4", "5"]
a.scan(/-(\d+)-(\d+)$/)[0].try(:map, &:to_i) # => [4, 5]

Rails 3: How to get all Posts which ids are not in a given list?

To get all posts with publisher_id equals to 10, 16, or 17, I do:
Post.where(:publisher_id => [10, 16, 17])
How would I get all posts with publisher_id not equals to 10, 16, or 17 (i.e. all possible ids besides those three) ?
Just perform a :
Post.where(["publisher_id NOT IN (?)", [10, 16, 17]])
in rails 4 we can do like below
Post.where.not(:publisher_id => [10, 16, 17])
it will generate SQL like below
SELECT "posts".* FROM "posts" WHERE ("posts"."publisher_id" NOT IN (10, 16, 17))
Untested, but should be like (using metawhere gem):
Post.where( :id.not_eq => [10,16,17] )
Using "pure" ActiveRecord syntax sprinkled with Arel using Rails 3 you can do something like this:
Post.where( Post.arel_table[:publisher_id].not_in([10, 16, 17]) )
Every single answer on this page is wrong because none of these answers take care of ALL array cases, Especially arrays that have only one element.
Here is an example that will FAIL using any of the 'so called' solutions on this page:
#ids = [1]
Post.where("publisher_id NOT IN (?)", #ids)
#ERROR
Post.where("publisher_id NOT IN (?)", [4])
#ERROR
#...etc
#ALSO
#ids = []
Post.where("publisher_id NOT IN (?)", #ids)
#ERROR
Post.where("publisher_id NOT IN (?)", [])
#ERROR
#...etc
#The problem here is that when the array only has one item, only that element is
#returned, NOT an array, like we had specified
#Part of the sql that is generated looks like:
#...WHERE (publisher_id NOT IN 166)
#It should be:
#...WHERE (publisher_id NOT IN (166))
The only answer on this page that is actually on the right track and takes care of this very important case is #Tudor Constantin's. But the problem is he didn't actually show a 'way' of using his methodology to solve the real abstract example question the OP posted (not just using the hard-coded numbers).
here is my solution to dynamically find the ids not in an Activerecord association given an array of ids to exclude, that will work with an array of n elements (...including n=1 and n=0)
#ids = [166]
#attribute = "publisher_id"
#predicate = "NOT IN"
#ids = "(" + #ids.join(",") + ")"
if #ids == "()"
#Empty array, just set #ids, #attribute, and #predicate to nil
#ids = #attribute = #predicate = nil
end
#Finally, make the query
Post.where( [#attribute, #predicate, #ids].join(" ") )
#Part of the sql that is generated looks like:
#...WHERE (publisher_id NOT IN (166))
#CORRECT!
#If we had set #ids = [] (empty array)
#Then the if statement sets everything to nil, and then
#rails removes the blank " " space in the where clause automatically and does
#the query as if all records should be returned, which
#logically makes sense!
If this helped you in anyway, please up vote! If you are confused or don't understand one of my comments, please let me know.
Neat solution I've used:
ids = #however you get the IDS
Post.where(["id not in (?)", [0,*ids])
The presence of the 0 means it always has one element in (assuming nothing has an ID of 0)
ID becoming a splat means it'll always be an array.
Post.where(" id NOT IN ( 10, 16, 17) ")

Ruby on Rails: remove element from array by id

Is there some sort of short hand for
#notifications = Notification.find(:all, :conditions => ['expires_at > ?', Time.now])
notif = Notification.find(:all, cookie[0].to_i)
#notifications.delete(notif[0]) if not notif.empty?
cookie is an id of a notification stored into cookies.
this is in an iteration, that removes notifications that the user doesn't want to see.
thanks! =)
If this is an array of activerecord objects, you could delete from the database like this.
Notification.delete_all(:id => cookie[0].to_i)
If this is just an array, then you can use the delete if
#notifications.delete_if{|x| x == cookie[0].to_i}
Now you could just use the delete_at( index ) method:
array = ['item0', 'item1', 2, 3]
array.delete_at 1
# => "item1"
array.delete_at 2
# => 3
array
# => ["item0", 3]
You could do the same with slice!( index ).
Note: delete_at is a mutator method even if it doesn't end in !, so don't rely on its return value, it will only be the deleted item.
Reference:
http://ruby-doc.org/core-2.2.0/Array.html#method-i-delete_at

Resources