Rails: How to Use Scope to Find an Element in Array of Arrays

Make a Scope condition check if an Array has at least one element of another array

If this is PostgreSQL then you'd want to use the && (overlaps) operator:

&&
overlap (have elements in common)

ARRAY[1,4,3] && ARRAY[2,1]
t

You'll also want to use the array constructor syntax:

array[?]

as ActiveRecord likes to expand placeholders whose values are arrays as a list of comma separated values.

Putting that together, your scope could look like:

def self.with_uses(uses)
where('buildings.types_of_use && array[?]', uses)
end

or, if you prefer to use the scope method to define scopes:

scope :with_uses, ->(uses) { where('buildings.types_of_use && array[?]', uses) }

but "Using a class method is the preferred way to accept arguments for scopes" so I usually use explicit class methods for scopes with arguments.

Rails scope with array as argument Rails 4

Since a scope is just syntactic sugar for a Class method anyways, I would recommend just creating it as a class method and the whole thing becomes much easier/cleaner:

class Member < ActiveRecord::Base

self.find_by_full_name(array_of_names)
members = []

array_of_names.each do |name|
split_names = name.split(' ')
members.push(Member.find_by_first_name_and_last_name(split_names.first, split_names.last))
end

members.compact
end

end


UPDATE

And then you could even extend the capabilities of it easily (one additional line) if you wanted it to be able to accept either a single name or an array of names:

class Member < ActiveRecord::Base

self.find_by_full_name(names)
members = []
names = [names] if names.is_a?(String)

names.each do |name|
split_names = name.split(' ')
members.push(Member.find_by_first_name_and_last_name(split_names.first, split_names.last))
end

members.compact
end

end


NOTE

Not sure if you're familiar with .compact but that will accomplish the "if it exists" portion of your question. The Member.find_by... will push a nil value onto members if there isn't a match, and then .compact will remove the nil values from members.

How can I use a named scope in my model against an array of items?

If you pass an array as the value, ActiveRecord is smart enough to compare for inclusion in the array. For example,

Book.where(:author_id => [1, 7, 42])

produces a SQL query with a WHERE clause similar to:

WHERE "author_id" IN (1, 7, 42)

You can take advantage of this in a scope the same way you would set normal conditions:

class Book < ....
# Rails 3
scope :by_author, lambda { |author_id| where(:author_id => author_id) }

# Rails 2
named_scope :by_author, lambda { |author_id
{ :conditions => {:author_id => author_id} }
}
end

Then you can pass a single ID or an array of IDs to by_author and it will just work:

Book.by_author([1,7,42])

Rails scope where clause find nested array value in hash

Get users with a car in recent_purchases

User.where("info -> 'recent_purchases' ? :car", car: car)

Get users with only a car in recent_purchases

User.where("info -> 'recent_purchases' = to_jsonb(array[:car])", car: car)

an alternative to the previous example

User.where("info -> 'recent_purchases' ? :car and jsonb_array_length(info -> 'recent_purchases') = 1", car: car)

If info is json instead of jsonb then cast it to jsonb

info::jsonb

See PostgreSQL documentation for more ways to query against json/jsonb:

https://www.postgresql.org/docs/9.5/functions-json.html

How do I find an index of an element in an array matching a condition and starting the search from a particular point in the array?

Using select would return all values where the block returns true for example:

p arr = ["abc", "d", "efg", "h", "abcde", "k"]
# => ["abc", "d", "efg", "h", "abcde", "k"]
p arr.each_index.select{|i| i >= 2 and arr[i].length == 1}
# => [3, 5]

Instead use detect if you want to return only the first value where the block returns true:

p arr = ["abc", "d", "efg", "h", "abcde", "k"]
# => ["abc", "d", "efg", "h", "abcde", "k"]
p arr.each_index.detect{|i| i >= 2 and arr[i].length == 1}
# => 3


Related Topics



Leave a reply



Submit