Rails: cache.fetch vs cache.read/write - ruby-on-rails

is there any performance difference between
Rails.cache.fetch("key") { Model.all }
and
models = Rails.cache.read("key")
if models.nil?
models = Model.all
Rails.cache.write("key", models)
end
If I must guess, i would say the upper one is just a shorthand for the other one.

If you check the source code, you'll notice that fetch does nothing more than call read and write.
Since it does some other operations (like checking if a block has been given, etc.) one could say that fetch is heavier, but I think it's totally negligible.

Related

Rails - Returning all records for who a method returns true

I have a method:
class Role
def currently_active
klass = roleable_type.constantize
actor = Person.find(role_actor_id)
parent = klass.find(roleable_id)
return true if parent.current_membership?
actor.current_membership?
end
end
I would like to return all instances of Role for who this method is true, however can't iterate through them with all.each as this takes around 20 seconds. I'm trying to use where statements, however they rely on an attribute of the model rather than a method:
Role.where(currently_active: true)
This obviously throws an error as there is no attribute called currently_active. How can I perform this query the most efficient way possible, and if possible using Active Records rather than arrays?
Thanks in advance
It seems impossible, in your case you have to do iterations. I think the best solution is to add a Boolean column in your table, so you can filter by query and this will be much faster.
After seeing your method after edit, it seems that it's not slow because of the loop, it is slow because Person.find and klass.find , you are doing alot of queries and database read here. (You better use associations and do some kind of eager loading, it will be much faster)
Another work-around is you can use ActiveModelSerializers , in the serializer you can get the attributes on the object based on condition. and after that you can work your logic to neglect the objects that have some kind of flag or attribute.
See here the documentation of active model serializer
Conditional attributes in Active Model Serializers
Wherever possible you better delegate your methods to SQL through activerecord when you're seeking better efficiency and speed and avoid iterating through objects in ruby to apply the method. I understand this is an old question but still many might get the wrong idea.
There is not enough information on current_membership? methods on associations but here's an example based on some guess-work from me:
roleables = roleable_type.pluralize
roleable_type_sym = roleable_type.to_sym
Role.joins(roleables_sym).where(" ? BETWEEN #{roleables}.membership_start_date AND #{roleables}.membership_end_date", DateTime.current).or(Role.joins(:person).where(" ? BETWEEN persons.membership_start_date AND persons.membership_end_date", DateTime.current))
so you might have to re-implement the method you have written in the model in SQL to improve efficiency and speed.
Try the select method: https://www.rubyguides.com/2019/04/ruby-select-method/
Role.all.select { |r| r.currently_active? }
The above can be shortened to Role.select(&:currently_active?)

Proper usage of `rescue` (or `try`)

When I have a model attribute that may or may not exist and I need to chain some methods after it, I add present?. For example:
Car.last.passengers.present? and
Car.last.passengers.each do { |passenger| puts passenger.name }
Would it be better to instead use rescue in such cases? For example
Car.last.passengers.each { |passenger| puts passenger.name } rescue "No passengers in the car!"
EDIT:
Thanks for all the responses. I should have asked a more general question, "What is the best way to handle a potentially nil result in the middle of a chain of methods?".
Let me make my example more general for clarity. If I call:
Car.last.driver.pocket_contents
but the last instance of Car has no driver, I'd be calling pocket_contents on nil. As per one of the commenters below, should I be using try, and if so, could you show me how it would be used succinctly in this case?
There is absolutely no reason to use rescue here. Using exception handling mechanisms for flow-control is widely viewed as an abuse of exceptions and generally considered a bad practice.
There is also probably no reason to use x.present? && x.each, as (if this is an ActiveRecord association) it will never return a falsy "non-present" value. It will always return an array-like object representing 0 or more items, which you can safely invoke each on. If this is not a ActiveRecord association, you should change your code to follow this convention and return an empty array instead of nil.
In the general case (assuming ActiveSupport::CoreExtensions is available), you can use try. Assuming passengers is a method that may return nil, your .present? checks should be try invocations:
Car.last.passengers.try(:each) { ... }
This can be chained to artibtrary lengths; both of these are equivalent:
a && a.b && a.b.c
a.try(:b).try(:c)
Note that this will not work if your method isn't returning nil, but instead returning a "blank" value.
If try is not available, your currently solution is a widely used practice, except that you should be using && instead of and - These are not equivalent operators in Ruby.
Car.last.passengers && Car.last.passengers.each { ... }
If you want to save characters, you can use || instead of && to supply a default value before you resort to the dirty rescue trick you're currently considering:
(Car.last.passengers || []).each { ... }
If this is an ActiveRecord association, there are several idiomatic Rails solutions, the best of which is to move your "puts" (which I'm assuming in reality is rendering a series of HTML elements) into its own partial, called _passenger.html.erb. Then, you can render the entire collection:
= render Car.last.passengers
If you want to handle rendering an empty set differently, you should depend on render's behavior of returning false when an empty collection is rendered:
= render Car.last.passengers || render 'no_cars'
This way, your markup for displaying a "There are no passengers" message to the user is stored in a _no_cars.html.erb partial and rendered cleanly with a single line.
You don't want to rescue an exception that should occur. If it is expected behavior that the attribute may not exist or the object may be nil then you may want to use either the try or try! methods.
This will try to call the method/attribute if your object is not nil. The try method will quietly evaluate to nil if somewhere along the chain it can not complete. The try! method will raise a NoMethodError if you try to call a method that doesn't exist on a non nil object.
http://apidock.com/rails/v4.2.1/Object/try%21
http://apidock.com/rails/Object/try
I can't tell where the code in your question lives, but I'll assume you are trying to list passenger names in a view. If you make passengers a collection in the controller:
#passengers = #car.passengers.all
Your _passenger.html.erb partial might read:
<%= passenger.name %>
You can render the collection in your view pass in a message if the collection is empty:
<%= render(#passengers) || "No passengers in the car!" %>
More about this here: http://guides.rubyonrails.org/layouts_and_rendering.html#using-partials

Ruby partially retrieve large amount of records and iterate over them

I'm newbie in Ruby but I have a lot of experience in other programming languages. I need to iterate over large amount of records (from db or any persistent storage). Storage engine allows me to retrieve records partially by ranges. In PHP I usually write custom iterator that loads range of records iterate over them and when need loads next part of records and forget about previous part. Some trade-off between script memory usage and count of request to storage. Something like this (copied from comments here):
class Database_Result_Iterator {
...
private $_db_resource = null;
private $_loaded = false;
private $_valid = false;
function rewind() {
if ($this->_db_resource) {
mysql_free($this->_db_resource);
$this->_db_resource = null;
}
$this->_loaded = false;
$this->_valid = false;
}
function valid() {
if ($this->_loaded) {
$this->load();
}
return $this->_valid;
}
private function load() {
$this->_db_resource = mysql_query(...);
$this->_loaded = true;
$this->next(); // Sets _valid
}
}
How such approach is transformed in Ruby? I.e. I have some class Voter and method get_votes that returns all votes belong to current voter object. It is possible to retrieve not an array with all votes but collection of votes with possibility to iterate over it. How should I implement it?
UPDATE
Please not consider ActiveRecord and RDBMS as only one possible storage. And what about Redis as storage and commands like LRANGE? I'm interested in common code pattern for solution such kind of problem in Ruby.
From the guides on Ruby on Rails:
User.all.each do |user|
NewsLetter.weekly_deliver(user)
end
Is very innefficient. You probably want to do most of the filtering in the database, to start with. ActiveRecord offers a method called find_each for this:
User.find_each(:batch_size => 5000) do |user|
NewsLetter.weekly_deliver(user)
end
The :batch_size parameter allows to fetch slices of data instead of getting the entire resultset. Extremely helpfull in most cases.
But, you probably don't want to operate on all records in the first place:
User.with_newsletter.each do |user|
NewsLetter.weekly_deliver(user)
end
Where with_newsletter is a so called scope.
I really don't see the point of this question.
AR is an API for querying RDBMS and that's how you do it in AR.
If you want to do redis you'll have to either write it yourself at the driver level or find a similar abstraction to AR for Redis... I think DataMapper had a redis adapter.
If there is a universal way to do this for any data store it is likely in DataMapper, but the basic pattern to follow when creating your own would be to look at how AR implements find_each/find_in_batches and do it for your store of choice.
It sounds like you want to use find_each (http://apidock.com/rails/ActiveRecord/Batches/ClassMethods/find_each). This lets you iterate through a large dataset by loading in a small number, iterating over them, then loading in another batch and so on.
User.find_each do |user|
user.do_some_stuff
end
will iterate through all users without loading a bajillion of them into memory at once.

grails delete all data from table / domain class, i.e. "deleteAll"

I've got a domain class, Widget, that I need to delete all instances out of -- clear it out. After that, I will load in fresh data. What do you suggest as a mechanism to do this?
P.S. Note this is not at bootstrap time, but at "run-time".
The easiest way is to use HQL directly:
DomainClass.executeUpdate('delete from DomainClass')
DomainClass.findAll().each { it.delete() }
If you want to avoid any GORM gotchas, such as needing to delete the object immediately and checking to make sure it actually gets deleted, add some arguments.
DomainClass.findAll().each { it.delete(flush:true, failOnError:true) }
Fairly old post, but still actual.
If your table is very large (millions of entries), iterating using findall()*.delete() might not be the best option, as you can run into transaction timeouts (e.g. MySQL innodb_lock_wait_timeout setting) besides potential memory problems stated by GreenGiant.
So at least for MySQL Innodb, much faster is to use TRUNCATE TABLE:
sessionFactory.currentSession
.createSQLQuery("truncate table ${sessionFactory.getClassMetadata(MyDomainClass).tableName}")
.executeUpdate()
This is only useful if your table is not referenced by other objects as a foreign key.
From what I learnt, I agree with #ataylor the below code is fastest IF there are no associations in your domain object (Highly unlikely in any real application):
DomainClass.executeUpdate('delete from DomainClass')
But if you have assiciations with other domains, then the safest way to delete (and also a bit slower than the one mentioned above) would be the following:
def domainObjects = DomainClass.findAll()
domainObjects.each {
it.delete(flush:it==domainObjects.last, failOnError:true)
}
If you have a list of objects and want to delete all elements, you can use * operator.
'*' will split the list and pass its elements as separate arguments.
Example.
List<Book> books = Book.findAllByTitle('grails')
books*.delete()

Rails difference in object created from a .find(:id) and .where() methods

What is the difference in the objects created with these 2 methods:
tec = Technique.find(6)
tec2 = Technique.where(:korean => 'Jok Sul')
The data returned for each is exactly the same, yet the first object will respond perfectly to an inherited method like update_attributes while the second object will give an error of method not found.
When I do tec.class and tec2.class one is an ActiveRecord::Relation and the other doesn't give me a class at all, it just prints out the content of the object.
Maybe when you use the .where method you get an array, even if there is only one match and therefore you always have to issue the .each method to get at the contents? But that makes it hard to deal with when you want to update records, etc.
Can someone clarify this for me? Specifically, how to deal with matches found through the .where method.
Thanks.
Try:
tec2 = Technique.where(:korean => 'Jok Sul').first
Good question.
tec_scope = Technique.where(:korean => 'Jok Sul') # create an internal query
Remember, here only the query is created, it is not executed. You can programmatically build on top of this query if you so wished. The scope (or query if you so wish) will be executed in 2 ways. "Implicit" or "Explicit". Implicit way of running the query happens for example in the console, which invokes a method on the scope which automatically runs the query for you. This wont happen in your controllers unless you run it explicitly for .e.g
tec_scope.all # returns array
tec_scope.first # retuns one element
Scopes are just adding where clauses/predicates to your query. It's query building and delaying the execution till it is needed.
However,
tec_objects = Technique.find(6) # explicitly runs a query and returns one object (in this case)
This will explicitly run the query there and then. It is a question of the timing of execution of the query.
The difference is subtle but very important.
This hasnt got anything to do with whether you get one result or an array.
Technique.find([4,5]) # will return an array
Technique.find(4) # will return one object
Technique.where(:some_key => "some value").all # will return an array
Technique.where(:id => 5).first # will return one object
The difference is in timing of the execution of the query. Don't let the console fool you into believing there is no difference. Console is implicitly firing the query for you :)
The find(6) returns a single object, because you're specifying the object ID in the database, which is guaranteed to be unique by convention.
The where call returns a collection, which may be only 1 item long, but it still returns a collection, not a single object.
You can reveal this difference. Using your example code, if you call tec.class vs. tec2.class I think you'll find that they aren't the same class of object, as you expect.
That is, the methods available to a collection of objects is different than the methods available on an instance of that object.

Resources