Group all records by custom method in Rails - ruby-on-rails

I'd like to retrieve all records for a particular model and "index" each one by their name attribute. The end result should be a Hash, where the keys are the name of the record, and the value is the record. I can do this easy enough with a method like
def self.all_by_name
hash = {}
all.each { |model| hash[model.name] = model }
hash
end
Is there a way to do this with an active record query?

all.group(:name) is what you need!
Some documentation: http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-group

No, active record will either return an array or an active record relation. You would have to massage it after into the data type of your choice. ActiveRecor dcan return anything that SQL can normally return. However, you could do use the group method which is essentially the group by in SQL.
I'm not sure in your case what your method should do because it seems like you are going to overwrite the value of your key if there are 2 objects with the same class. Perhaps if you better defined what you need in an example I could help you better.

Related

Is it possible to update an entire record using an object in rails?

I was wondering if I could update a record (entire row) given a replacement activerecord object.
Something like
Car.find_by(number: 1) = replacement_information_for_car_1
where replacement_information_for_car_1 is a Car activerecord object that I would like to use to replace the old record currently on the table.
You could do something like:
attributes = replacement_information_for_car_1.attributes
attributes.delete('id') # and anything else you don't want/can't be copied
Car.find_by(number: 1).update(attributes)
Not the cutest thing in the world, but it should do the trick.
The thing about ActiveRecord objects is that they have a unique identifier that you don't want to override. You'll have to assign the attributes without the id, that is most likely to be nil in your example.
Car.find_by(number: 1).update(replacement_information_for_car_1.attributes.except(:id))
That's a long line that can be refactored to something like
new_attributes = replacement_information_for_car_1.attributes.except(:id)
Car.find_by(number: 1).update(new_attributes)

Rails - finding an object in an active record association by an attribute without issuing more queries

Very short question, I feel like the answer must be already on StackOverflow but I couldn't find it.
I have some incoming parameters. They each have a unique ID.
I query the database and get an active record association using something like:
existing_things = current_user.things.where(uuid: [param_uuids])
This gives me an Active Record Association of those objects.
However, what I later do is something like:
existing_things.where(uuid: some_specific_uuid)
Of course, when I run the above query, it issues an SQL statement.
What I would love to do is find an object in a pre-loaded Active Record array of objects, and return that object without issuing another query.
How should I do that?
The same way you would if it was an ordinary array: Enumerable#find.
existing_things.find { |t| t.uuid == some_specific_uuid }
(or select if you're expecting more than one match)
If you're doing a lot of lookups like that, you might want to get a Hash involved:
things_by_uuid = existing_things.index_by(&:uuid)
things_by_uuid[some_specific_uuid]
(again, if you're expecting more than one match per value, there's group_by)

How do I retrieve a record by ID from an Active Record record collection?

If I have a collection of records returned from an Active Record query, how can I access one of those records if I know its ID?
There are two ways to do this. Assuming you have an ActiveRecord relation called records and are searching for id:
You can use the ActiveRecord::FinderMethods#find method, but this will result in another call to the database:
records.find(id)
You can search through the collection without using the database by calling Ruby's Enumerable#find method as follows:
records.find { |r| r.id == id }
Although they share the same name, we are invoking two different find methods in the above example. The first will use more database resources, while the latter will use more application server resources. I am not sure which one is faster in the end.
TableName.find(id)
should do it.
Or if you already have a bunch of records in an Active Record query you can pull out the one with the known id like:
active_record_query = User.where(first_name: "Jim")
record = active_record_query.where(id: record_id).first
Supposing I have a result set of users and I want to find the user with ID = 3 in that set:
foo = User.all
user3 = foo.find {|x| x.id == 3}
Of course if you know the ID, you could just find it. Supposing I have a users table and I know the ID of the user I want is 3:
user3 = User.find(3)
You can find records with from the database with ActiveRecord::FinderMethods#find.
Thing.find(1) will query the database for SELECT things.* FROM things WHERE things.id = 1. And raise an ActiveRecord::NotFoundError if the record cannot be found. Find can also be used with a list of ids.
If you have a relation that is already loaded from the database you would use Enumerable#find or its alias #detect. ActiveRecord::Relation includes Enumerable so it works even if you don't explicitly cast to an array with .to_a.
Passes each entry in enum to block. Returns the first for which block
is not false. If no object matches, calls ifnone and returns its
result when it is specified, or returns nil otherwise.
Example:
[1,2,3,4].find(&:even?) # => 2
User.all.load.find { |u| u.id == 1 }
Yes. You can use the find method.
# Assuming you were retrieving an ActiveRecordRelation s
s = MyRecord.where(name: "test")
s.find(id)
For further information see: http://api.rubyonrails.org/v5.0/classes/ActiveRecord/FinderMethods.html#method-i-find

Active record where query for value inside of an array

Question: Is it possible to build a class method scope that can query objects based on values inside an array in a table? If yes, how can I do this?
In my example, I have a “wells” table that has an array field called “well_tags”. I want to build a query that returns all objects that have a specified value (such as “ceramic”) in the wells_tags array. The basic query would be something like this:
#well = Well.all
#query = #well.where(“well_tags contains ceramic”)
And then the class method scope would look something like this, with the “well_tag_search” param passed in from the controller:
class Well < ActiveRecord::Base
def self.well_tag_filter(well_tag_search)
if well_tag_search.present?
where(“well_tags contains ceramic")
else
Well.all
end
end
I found another post that asks a similar question (see link below), but I cannot get the answer to work for me...the result is always 'nil' when I know there should be at least 1 object. I am a beginner using sqlite (for now) as my database and rails 4.0.
Active Record Query where value in array field
Thanks!
UPDATE: some progress
I figured out how to create an array of all the objects I want using the ‘select’ method. But I still need to return the results as an Active Record object so I create a class method scope.
#well = Well.select
{ |well| if well.well_tags.present?
then well.well_tags.include? ‘ceramic' end }
#well.class #=> array
Not sure where Show is coming from.
Can you try doing Well.all instead of Show.all?

Trouble on finding a class object in a array of classes

I am using Ruby on Rails 3.0.7 and I would like to understand how to handle the following code in order to retrieve a class objects with a specified id.
In my view file I have:
#records = Users.all # This returns an array (class)
In another file, a partial template, I would like to retrieve, for example, the user with id 1, but if I make this:
#records.find(1)
I get an enumerator (class) of all records:
<Enumerator: [<Users id: 1, ... ] >
How can I find the user with id 1 (or other ids) "a là Ruby on Rails Way"?
UPDATE
I use #records = Users.all in a view file because I aim to minimize calls to the database since I need to iterate almost over all records and check them existence. If I do for example:
some_hash.each { |key, value|
put User.find(value)
}
and I go in the log file, I will see a lot of database requests.
Even though this is probably quite slow, and I suspect there are some less than optimal designs in the app you're working on (not judging, we've all been there), Array#index seems to be what you're looking for:
#records[#records.index{|user| user.id == 1}]
Edit
Although if you need to do something for every user, and you need to access them by id quickly, I'd probably do something like this in your controller. Even if it's not really faster, it's much more readable (to me anyways):
#users_hash = {}
User.all.each{|user| #users_hash[user.id] = user}
Then in your views you can do:
#users_hash[id].username
Use User.scoped instead of User.all. #all will immediately query the database and return an array, whereas #scoped will return an ActiveRecord::Relation object which you can chain further queries. In this case, the database won't be hit until you try and somehow inspect or enumerate the result
Actually you're mistaken. #records.find(1) is returning an object of the class Enumerator (which is not the same as the class Enumerator itself).
The problem here is that, as you've noted, #records is an Array, not an ActiveRecord object, and Array#find (inherited from Enumerable#find--which, when not given a block, returns an object of class Enumerable) is not the same method as ActiveRecord::Base#find (i.e. User#find).
What you should do is, in your controller, pick out the one user record you want:
#user = User.find 1
...and then use #user directly in your template. Generally you should avoid doing ActiveRecord lookups (e.g. find) in your templates. That kind of logic should happen in your controller.
Last time for such case I ended up doing like this:
#assignments = Assignment.find_by_sql(' ... ')
#assignments.find(id: 1).first

Resources