class ViewJob
##counter = 0
def initialize
...
end
end
Do all Resque job instances of this class share the same ##counter? Or is there any other way to share variables in Resque jobs (I'm not a fan of global variables)?
It is Ruby, thus class variables behavior would not differ in any way.
General rule of class variables - if you're not sure you know you are using class variable right - do not do that. Even if you are sure - you most likely do not need it.
Related
I have a rails 4 app that has an alert model and tests associated to each alert.
When a new alert is created I have a an after_create filter that uses an instance method to create a new test:
class Alert < ActiveRecord::Base
has_many :tests
after_create :create_test
private
def create_test
#bunch of code using external api to get some data
Test.create
end
end
I also have a cron job that I want to use to create a new test for each alert. My plan was to have a class method to do that:
def self.scheduled_test_creation
#alerts = Alert.all
#alerts.each do |a|
a.create_test
end
end
That won't work because the instance method is private. I know I can get around this using send for example. Or I can make the methods public. Or I can rewrite that bunch of api code in the instance method.
I am just not sure what the best way would be. I don't want to write the same code twice and I want to make sure is good practice. Maybe in this case the methods don't have to be private - I know the difference between public/private/protected but I don't really understand when methods should be private/protected.
Any help would be greatly appreciated
I like service classes for interactions between multiple models. Callbacks can make the logic quite hard to follow.
Eg:
class AlertCreator
def initialize(alert)
#alert = alert
end
def call
if #alert.save
alert_test = TestBuilder.new(#alert).call
alert_test.save
true
end
end
end
class TestBuilder
def initialize(alert)
#alert = alert
end
def call
# external API interaction stuff
# return unsaved test
end
end
Inside your controller, you'd call AlertCreator.new(#alert).call instead of the usual #alert.save.
I agree with #SergioTulentsev: while in the long run you may be better served by breaking out this logic into a service class, in the short run you simply shouldn't make a method private if it needs to be called outside of the instance.
In some cases you actually want to access a private method, for example when verifying object state during tests. This is easy to do:
#alert.instance_eval{ create_test }
You can even fetch or alter instance variables this way:
#alert.instance_eval{ #has_code_smells = true }
In general, if you feel the need to do this, it's a warning smell that your logic needs to be rethunk. Ignoring that sort of smell is what turns Ruby from a wonderful language into a way-too-powerful language that allows you to shoot yourself in the foot. But it's doable.
I understand what these statements do, but not how to refer to them. They exist within a class, outside of that class's methods and perform a variety of functions.
Collectively, what are they called?
These methods are really just class methods. Try this:
class Test
def self.before_create
puts "before_create"
end
before_create
end
The specific use case you mentioned - Rails DSL methods such as before_create, that are only available inside a class body — are often called class macros. Rubys metaprogramming abilities give you multiple ways to build them. A simple one is to make them private:
module Foo
private
def before_create
puts "before_create"
end
end
class Bar
extend Foo
before_create
end
before_create is now accessible inside the class body, but not from outside:
Bar.before_create
NoMethodError: private method `before_create' called for Bar:Class
In pure Ruby terms, they are all just method calls.
However, they do have a common theme. In the way they are constructed and used, you could consider them part of a Domain-Specific Language (DSL) - the ones you list are part of Active Record's DSL for creating data models.
Ruby lends itself well to creating DSL-like mini languages, using mix-ins or a base class in order to provide a set of class methods, which in turn will store data or create methods on the class and instances of it using meta-programming techniques.
Im using Sidekiq, Redis, Websocket-rails inside of Rails. With sidekiq having server-side Class. Now, when adding more functionality, i cant anymore use instance variables inside my Sidekiq Class's methods, i need to share information between methods. Sidekiq class also inherits from Websocket class, to be available websockets.
Right now, i have 2000/per second data change for objects. Using 95% instance variables, 5% pushing/getting from Redis, to make lower I/O.
Im considering, using class variables or making all 100% on Redis. Im not sure about or it wont overload my background jobs with that big data transfer count, which goes bigger with every new client. I'm using heroku free Dyno, dont want to buy better server yet. But using class variables would be less I/O, and probably unsafe, becouse it inherits from Websocket-rails? Im doing this project partly to show something to employers, that i can program, to get my 1-st IT job. I care how they react to those class variables. What employers would say about class variables? And which one to choose?
You can absolutely use instance variables in your Sidekiq worker. You cannot use class or class-instance variables.
class MyWorker
include Sidekiq::Worker
def perform(a, b)
#a = a # instance variable, no problem!
##a = a # class variable, big problem!
self.set_a(a)
end
def self.set_a(a)
#a = a # class instance variable, big problem!
end
end
Class variables have their places, if they represent a concept that is unchangeable and should live as a definition of something, like a configuration throughout the application, or some fundamental multiplier of a part of the application domain/business.
But, just because things are unchanging, that doesn't mean they have to be a class variable. You can have an instance of a class to be always setup with the same values, and then share the instance. Kind of like a singleton, but not necessarily being a singleton, just being a widely shared variable that is part of the input on the start of a given process.
So instead of using Sidekiq to store data for this unchanging thing, and rather than using class variables, you can achieve a cleaner design by doing something like
class ImportantThing
def initialize(name, other_property)
#name = name
#other_property = other_property
end
# Other methods you wish to define the behavior of the thing
end
then you can
the_important_thing = ImportantThing.new("foobar", 3.46)
do_important_process(the_important_thing)
then as far as the important process you are running is concerned, the important thing is anything that behaves like a important thing, and it doesn't matter if it is a globally setup or ever unchanging.
This makes for a easy to test architecture which is generally a sign of clear and decoupled design.
I have a bunch of classes that are resque jobs and I just noticed I have a constant defined in each named RECEIVER which contains the email distribution list for the jobs results.
What is the default behavior in ruby/rails if I have a constant RECEIVER = "emails" and have it defined in multiple classes. Each class assigns the value of RECEIVER to an instance of the class upon initialization.
Just trying to think of the best way to refactor something like this. thank you
It gets defined in each class separately. The best way to refactor to prevent code duplication would be to use a module
module CommonMethods
RECEIVER = "emails"
end
and then in your class:
class SomeClass
include CommonMethods
#do stuff
end
That way the email list is only defined in one place.
You could also define other methods in here that are common to all of your classes.
I am getting confused as to how to properly set variables in a initializer, I want these to be class level variables, not instance.
And I also want to then create a single instance of another object (it is a connection object, which already has connection pooling built in, so I just need a single reference to it).
My initializer /initializers/my_class.rb
yml = YAML.load_file("#{Rails.root}/config/my_class.yml")
MYMODULE::MyClass.init(yml)
And here is my my_class.rb:
module MYMODULE
class MyClass
def self.init(yml)
#post_url = yml["defaults"]["post_url"]
end
def self.post_url
#post_url
end
# this should be a single instance
def connection_pool
# ???
end
end
end
These class level variables, how can I access them from both class methods and instance methods?
I'm getting wierd behaviour, and I'm confused as to how to reference the post_url from inside of either class methods and instance methods.
I have seen the following ways, unsure which is correct:
self.class.post_url
MyClass.post_url
#post_url
post_url
self.post_url
self.class.post_url or MyClass.post_url will work. The difference is how they work for subclasses (in the former case, subclasses will use their own version of this variable automatically, in the latter, they would share the variable in MyClass).
There is no way to directly access class instance variables from an instance: you have to call a class method which returns (or sets) them. See also: cattr_accessor.
That said, if this is really a singleton, it seems a little strange to me that you would configure part of it on the class, and then reference that info in the (single) instance. Wouldn't it make more sense just to configure this stuff on the instance? Or use a module as a singleton and not create an instance at all?