0

I have the following model in Ruby

class Entity < ActiveRecord::Base
  validates :account_type, presence: true
  validates :account_id, presence: true
end

and I have an array of hashes called accounts something like:

[{'account_id':44, 'account_type':'user'},..,{'account_id':44, 'account_type':'other'}, {'account_id':88,
'account_type':'another'}]

So I want a way to obtain all the entities that match with the elements of the accounts array (account_id and account_type both at same time).

I tried using this code:

entities = []
accounts.each do |account|
    entities << Entity.where(account_id: ActiveSupport::HashWithIndifferentAccess.new(account)['account_id'])
    .where(account_type: ActiveSupport::HashWithIndifferentAccess.new(account)['account_type'])
end

But there is a way to do it more efficient ??

2
  • Since you want a record to match both attributes at the same time, then I can't think of a better way. However there may be a better way to accomplish whatever you are trying to do. Maybe there is an issue with the logic you followed that brought you to the need of that query and not the query itself. Commented Mar 19, 2019 at 22:04
  • 1
    Do you need to cast as HashWithIndifferentAccess, if you are only accessing by string? The two where clauses look like they could be combined into where(account_id: account['account_id'], account_type: account['account_type]), or possibly where(account) if you trust the attributes. You could also use Entity.select('id, name').where() to reduce the number of fields pulled if you don't need them. Commented Mar 19, 2019 at 22:15

3 Answers 3

3

Given this:

[{'account_id':44, 'account_type':'user'}, {'account_id':44, 'account_type':'other'}, ... ]

the SQL you want is:

select ...
where account_id = 44 and account_type = 'user'
   or account_id = 44 and account_type = 'other'
   or ...

Note that SQL's operator precedence makes that the same as:

select ...
where (account_id = 44 and account_type = 'user')
   or (account_id = 44 and account_type = 'other')
   or ...

You can build a query like that using ActiveRecord but it is a little cumbersome due to the way #or works:

accounts = your_array_of_hashes
entities = accounts.inject(Entity.none) { |memo, h| memo.or(Entity.where(h)) }
Sign up to request clarification or add additional context in comments.

Comments

1

If you're using rails 5 you could try or. Something like this

entities = Entity.none
items.each do |item|
  entities = entities.or(Entity.where(item))
end

This is just one SQL query but if the array is big I don't know how this works.

Comments

0

If i got your problem, this should solve it:

entities = accounts.map { |acc| Entity.where(account_id: acc['account_id'], account_type: acc['account_type']) }

Let me explain what is happening:

  • first, the method map returns an array will all the entries that dit match with anything at the database
  • the map is interating through the accounts array, just like the each, which means it will bring the data at accounts to the where query
  • a comma between where conditions also works for comparisons, unless you are doing an or, in the case i suppose you can use this syntax: where('account_id = :id or account_type = :type', id: acc['account_id'], type: acc['account_type'])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.