Is there a technique that I can use in Rails so that whenever a simple "find" is performed on a Model object, memcached is first searched for the result, only if no result is found will a query by then made to the database?
Ideally, I'd like the solution to be implicit, so that I can just write Model.find(id), it first checks the cache and if a database query is required that the object returned is then added to the cache i.e. I don't need to wrap the Model.find(id) with additional code to check the cache for matching contents.
Thanks!
http://github.com/ngmoco/cache-money is the way to go
Related
I'm trying to generalize some logic to do some manipulation to a ActiveRecord::Relation. Issue is that the aim is to prevent authorization issues, so the flag needs to be set whenever a new ActiveRecord::Relation is instantiated or changed, but I'm not sure how to access the ActiveRecord::Relation data. I think some pagination gems might have a solution, but unsure.
Specific issue is that for Pundit we use something like:
policy_scope(Model)
Ignoring the specifics of exactly how policy_scope works (as it's pretty flexible), it might modify the query to use something like:
Model.where(user_id: current_user.id)
And yes, some care is needed to ensure it doesn't perform a union rather than an intersect on the ids, but that is another matter and handled within the policy itself.
To scope a Model or database query in general to a specific scope. I'd like to add a check on that to ensure and verify that all database queries are scoped. A way this could be done would be to add a flag of some sort to the query itself automatically an unflag it if is scoped, with an error being generated if the query is ran while it is flagged.
THe problem trying to solved here is that it can be very problematic if certain database queries are not scoped when it comes to multi-tenanting and other use cases.
I found the following in the FAQ after sorting out a bug.
It’s possible that you are trying to paginate a static Array instead of performing a paginated query in the database. For instance, chaining a paginate call after an Active Record find or all methods is wrong:
The above line will return the desired result but defeats the purpose of pagination. Here, the find query will first load all the records from the database, which is dangerous and should be avoided.
My question is why is it dangerous to paginate a find?
Pagination is meant to prevent unnecessary db load: you only want some elements from the db, so you only load them.
Using find you load everything then you kind of sort.
Dangerous == Heavy db load and thus potential crash.
In my project, i have a situation like when user runs the application.
The system should insert some values in a table which is used allover the application.
(These value should be inserted only once when the project is executed at first time)
I am trying to find out if there is any initialization function like Constructors in Rails.
I tried to use the config/application.rb, but i am not sure its the right way to do this.
Please suggest.
Thanks
If you looking for inserting some default dictionary data like month names etc you should look into seed.rb file or even better consider using seed_fu gem (https://github.com/mbleigh/seed-fu)
Yes you can insert/edit/delete records into table with migration :
1) Create the migration .
2) Run db query inside the execute. like :
execute "insert into users (name, role) values ('vik', 'admin')"
3) After all the insertion operation run the migration.
How if you update have boolean field or any kind of integer field to maintain status in your application. And for the very first time, user runs the application, your code will insert necessary values for that user in db and update boolean/status field and will be cached(for better performance only rather than fetching value from db every time). However after every time cache is cleared, it will send the query to db; but fetching boolean value(checking user status) is more faster than checking all inserted values for that user.
In a stats part of a Rails app, I have some custom SQL calls that are called with ActiveRecord::Base.execute() from the model code. They return various aggregates.
Some of these (identical) queries are run in a loop in the controller, and it seems that they aren't cached by the ActiveRecord query cache.
Is there any way to cache custom SQL queries within a single request?
Not sure if AR supports query caching for #execute, you might want to dig in the documentation.
Anyway, what you can do, is to use memoization, which means that you'll keep the results manually until the current request is over.
do something like this in your model:
def repeating_method_with_execute
#rs ||= ActiveRecord::Base.execute(...)
end
This will basically run the query only on the first time and then save the response to #rs until the entire request is over.
If I am not wrong, Rails 2.x already has a macro named memoization on ActiveRecord that does all that automatically
hope it helps
ActiveRecord query caching is enabled when a controller's action is invoked. I also know that you can do something like this to temporarily enable caching for a given Model for a given code block:
User.cache do
....
end
But is there a way to enable query caching for other contexts (e.g. when a script is run under the rails environment using ./script/runner)?
An ActiveRecord query cache lives only for the duration of a particular action (i.e. request). If you want a cached object to survive longer or be used between processes you need to look at something like memcached.
This plugin will persist the query cache using memcached.
A simple solution is to wrap the code given to script/runner in a block, directly on the commandline:
script/runner "User.cache { ... }"
Notice the caching is not simply for the User model, but for all queries performed within the codeblock.
To get query caching when running a script you need to wrap any code with:
ActiveRecord::Base.connection.cache do
your_code_here
end
It looks like rails automatically sets the query cache for normal calls to Actions, but you have to do it manually in other contexts.