Thread in rails for creating object - ruby-on-rails

In my controller, I have :
#a = Myobject.new params
#b = Myobject.new params2
In the models folder, I have a class (no a model) :
class Myobject
attr_accessor: :var1, :var2, :var3
def initialize params
# Some processes with SQL queries and classes variables.
#var1 = result_of_a_sql_query
#var2 = a_hash
#var3 = params[:varpost]
end
end
But it's slow.
I would like to launch this 2 object creations in parallel. (with thread or other)
I've tried :
t1 = Thread.new {#a = Myobject.new params}
#b = Myobject.new params2
t1.join
But I've got an error : Circular dependency detected while autoloading constant Myobject
How can I launch this 2 commands in parallel ?
Thank you.

If you are working with complex object creation, but you need to get a prompt response back to your user, then it may be best to actually queue your object creation jobs where they can be processed on the system's own time rather than going through the whole thing during your action.
You might look at the various background job gems available to you. On the current application I am working with, updates are dropped into a Resque queue asynchronously and then pulled out and actions performed on the database as possible. This approach can work very well and is fairly standard in cloud environments.
If you need the data available on the front, that would not work as well but you could create simple proxy objects to return most of the data in a view, or simply perform async updates and maintain a front-end version of the data model too.

Related

Is it inefficient to continually call the parent model for specific data attributes?

Let's say on some Child model method I need to do calculations based on some data stored on its Parent model. For example,
def child_method(minutes)
remaining_time = minutes % self.parent.parent_settings
if remaining_time >= 1
return minutes/ self.parent.parent_settings
else
return [minutes/self.parent.parent_settings - 1 , 0].max
end
end
In the above I've called self.parent.parent_settings 3 times. Based on how Rails works, is this efficient? Or is it a terrible idea, and I should instead set the parent_settings locally, e.g.,:
def child_method(minutes)
parent_settings = self.parent.parent_settings
remaining_time = minutes % parent_settings
if remaining_time >= 1
return minutes/ parent_settings
else
return [minutes/parent_settings - 1 , 0].max
end
end
I have more complex instances of this (e.g., where in one child method I'm accessing multiple parent attributes, and also in some instances, grandparent attributes). I realize the answer might be "it depends" on exactly what is the data, etc., but looking to see if there are general rules of thumb or convention
Like you said, it depends.
Rails will cache fetched associations as long as the object remains in memory:
puts self.parent.parent_settings.object_id
# ... Some code
puts self.parent.parent_settings.object_id # => This should be the same object ID as before
This cache is cleared automatically by the framework and can be explicitly cleared via #reload:
self.reload
Your code should be fine as long as you're not running child_method multiple times in a request/response cycle. Even if you do run child_method multiple times in the same request/response cycle, there's another database query cache that will intercept the same DB queries. The db query cache is only active when in production mode or when a special ENV var is set.

Rails move expensive method to task

I have these two methods in my model. One method looks up a single CatalogItem facebook like count, and another that loops through all active CatalogItems and finds their like counts using the aforementioned.
It takes a while to run through all active facebook likes...it might loop anywhere from 300-1000 objects; so i'd like to move this to some sort of cron, or whatever you guys suggest.
I was thinking I should add a column to CatalogItem called cached_fb_count, and adapt self.facebook_likes to write to that colimn whenever that task runs.
Is this the right approach? What would that task look like if it was running every 2 hours?
def self.facebook_likes
self.active.each_with_index do |i, index|
_likes = i.facebook_like_count
i.update_attribute(:cached_likes, _likes)
# puts "#{index+1} Likes: #{_likes} ########### ID: #{i.id} "
end
end
def facebook_like_count
item_like_count = JSON.parse(open("https://api.facebook.com/method/fql.query?query=select%20like_count%20from%20link_stat%20where%20url='https://www.foobar.com/catalog_items/#{self.id}'&format=json").read).first.flatten[1]
item_like_count = item_like_count + 1 if item_like_count > 0
end
Delayed_job is a perfect tool for doing asynchronous tasks. It runs in a separate process, relation database-based (Active Record) so it saves context of execution as a simple script invokation. And has a rich functionality inculding task's priority and scheldue. but If you tasks assumes huge queues, consider Resque gem. it uses Reddis as a storage for tasks and deals much faster with long queues.
Use whenever its very easy to set up. Here is the link : https://github.com/javan/whenever

ActiveRecord - working within one connection

For example, suppose there is the code in Rails 3.2.3
def test_action
a = User.find_by_id(params[:user_id])
# some calculations.....
b = Reporst.find_by_name(params[:report_name])
# some calculations.....
c = Places.find_by_name(params[:place_name])
end
This code does 3 requests to database and opens 3 different connections. Most likely it's going to be a quite long action.
Is there any way to open only one connection and do 3 requests within it? Or I want to control which connection to use by myself.
You would want to bracket the calls with transaction:
Transactions are protective blocks where SQL statements are only
permanent if they can all succeed as one atomic action. The classic
example is a transfer between two accounts where you can only have a
deposit if the withdrawal succeeded and vice versa. Transactions
enforce the integrity of the database and guard the data against
program errors or database break-downs. So basically you should use
transaction blocks whenever you have a number of statements that must
be executed together or not at all.
def test_action
User.transaction do
a = User.find_by_id(params[:user_id])
# some calculations.....
b = Reporst.find_by_name(params[:report_name])
# some calculations.....
c = Places.find_by_name(params[:place_name])
end
end
Even though they invoke different models the actions are encapsulated into one call to the DB. It is all or nothing though. If one fails in the middle then the entire capsule fails.
Though the transaction class method is called on some Active Record
class, the objects within the transaction block need not all be
instances of that class. This is because transactions are per-database
connection, not per-model.
You can take a look at ActiveRecord::ConnectionAdapters::ConnectionPool documentation
Also AR doesn't open a connection for each model/query it reuses the existent connection.
[7] pry(main)> [Advertiser.connection,Agent.connection,ActiveRecord::Base.connection].map(&:object_id)
=> [70224441876100, 70224441876100, 70224441876100]

Rails and class variables: will this persist across users and server calls?

We're on Rails 3.0.6.
Will the following code persist across page loads and users in Rails? Or does it get redefined with every request? The code lives at the top of a controller.
##list = []
hero = {}
hero['name'] = 'so'
hero['superpowers'] = ['coding', 'qa', 'spec_writing']
##list.push hero
hero2 = {}
hero2['name'] = 'so2'
hero2['superpowers'] = ['coding']
##list.push hero2
... more Hashes pushed into ##list
The list only changes once a month, and we would like to efficiently and quickly make this data available to page requests. We will eventually use Rails.cache to read from the database, but we're using the following approach for now (assuming it works).
In development, the default behavior is for the class to be reloaded on each request, thereby resetting your class variable. In production, however, the class is initialized once and so the class variable will persist across multiple requests and multiple sessions.
You should move to a proper caching technique as soon as you can. You cannot, obviously, persist the value beyond the reloading of the class when the application is restarted. Furthermore, if the web server is multi-threaded (as it is likely to be), it may be running multiple instances of the application on different threads which do not share the class variables, potentially creating inconsistencies between requests.
I've just came across the same issue and found this post. I know it's an old question, but posting my answer just in case someone else faces similar issue...
I think for cases where database or Rails.cache can not be used for some reason then the best place to put those values is Application class. Just define some attribute and initialize it. Then it's easy to access it just like Rails.application.heros. Quick and dirty sample below:
in config/application.rb
module YourRailsApp
class Application < Rails::Application
attr_reader :heros
initializer "init heros" do
#heros = []
hero = {}
hero['name'] = 'so'
hero['superpowers'] = ['coding', 'qa', 'spec_writing']
#heros.push hero
hero2 = {}
hero2['name'] = 'so2'
hero2['superpowers'] = ['coding']
#heros.push hero2
end
#Other application sutff...
end
end
I sometimes used what I called the cache of the poor.
It worked as follow:
in an initializer, add: MY_CACHE_HASH = {}
wherever you want: MY_CACHE_HASH[:foo] = :bar
wherever you need MY_CACHE_HASH[:foo] #=> :bar
I wouldn't recommend it though: what would you do if your server crashes?
If you have data that won't be changed while rails is running then it's fine to use a ##class_variable.
keep in mind that (in the default development configuration) controller classes are re-loaded at every request, so if you need to say, read the data from a file, consider putting the code to initialize the data into config/application.rb in a $global or CONSTANT_VAR.
So what you're describing is a datastructure that is not a database. I think it's perfectly reasonable to have items that "never" change in your code and not in your database.
for example, You could have:
In app/models/hero.rb
class Hero
##all_heros = []
def self.all_heros
##all_heros
end
def self.add_hero(hero)
##all_heros << hero
end
def initialize(name, superpowers=[])
#name = name
#superpowers = superpowers
end
end
# this will get executed on load
Hero.add_hero( Hero.new("so", ['coding', 'qa', 'spec_writing']))
Then later in your code, you'll access:
#heros = Hero.all_heros
And later you can swap out for a database backed store if you need on.

Delay a user defined helper method with delayed_job

So i have many database operations that i put into my helpers that i want to do in the background. As an example, I define a record_activity method in my Users helper. When a Post gets created I want to record this activity ie in the create method in the Posts controller:
def create
#operations to save the post
record_activity(user, post)
end
For performance reasons, I want to delay this record_activity and others, and run them with workers on the back-end. I use delayed_job for delaying mailers and it works excellently. In rails console, method.delay works great ie I could in rails console do:
record_activity.delay
However, the same .delay doesn't work when written in a controller ie the following still runs live, not delayed:
def create
#operations to save the post
record_activity(user, post).delay
end
Why is this? I'm using Rails 3.0.9 in one app and Rails 3.1.3 in another, plus I have delayed_job version 2.1.4.
Can anyone suggest how to make this work?
EDIT *
I think the answer provided by mu_is_too_short is the right path. It creates a delayed job, only it doesn't execute the record_activity method properly. When the delayed_job worker starts, it executes the delayed_job and has no errors, and deletes the record as if it worked. But no activity gets recorded. To give some context, here is the call and the method i am troubleshooting now:
self.delay.record_activity(user, #comment)
ANd the method:
def record_activity(current_user, act)
activity = Activity.new
activity.user_id = current_user.id
activity.act_id = act.id
activity.act_type = act.class.name
activity.created_at = act.created_at
activity.save
end
I then thought that maybe I couldn't pass user variables through, in this case, so I tried to just pass integer values and so on. I restarted the delayed_job workers and tried these methods, to no avail:
self.delay.record_activity(user.id, #comment.id, #comment.class.name, #comment.created_at)
And the altered method:
def record_activity(current_user_id, act_id, act_type, act_created_at)
activity = Activity.new
activity.user_id = current_user_id
activity.act_id = act_id
activity.act_type = act_type
activity.created_at = act_created_at
activity.save
end
I don't think record_activity.delay in the console is working the way you think it is. That will execute record_activity before delay has a chance to do anything.
The delay call has to go first, then you call your delayed method on what delay returns:
def create
self.delay.record_activity(user, post)
end
The delay call will return an object that intercepts all method calls (probably through method_missing), YAMLizes them, and adds the YAML to its delayed job queue table in the database. So, just saying record_activity.delay doesn't do anything useful, it just executes record_activity, creates the delayed-job interceptor object, and throws away what delay created.

Resources