Rails: monkey-patching ActiveRecord::Base vs creating a Module - ruby

I am reading through The Rails 4 way (by Obie Fernandez), a well-known book about Rails, and from what I've read so far, I can highly recommend it.
However, there is an example section 9.2.7.1: Multiple Callback Methods in One Class that confuses me:
Bear with me, to make the problem clear for everyone, I have replicated the steps the book describes in this question.
The section talks about Active Record callbacks (before_create, before_update and so on), and that it is possible to create a class that handles multiple callbacks for you. The listed code is as follows:
class Auditor
def initialize(audit_log)
#audit_log = audit_log
end
def after_create(model)
#audit_log.created(model.inspect)
end
def after_update(model)
#audit_log.updated(model.inspect)
end
def after_destroy(model)
#audit_log.destroyed(model.inspect)
end
end
The book says then that to add this audit logging to an Active Record class, you would do the following:
class Account < ActiveRecord::Base
after_create Auditor.new(DEFAULT_AUDIT_LOG)
after_update Auditor.new(DEFAULT_AUDIT_LOG)
after_destroy Auditor.new(DEFAULT_AUDIT_LOG)
...
end
The book then notes that this code is very ugly, having to add three Auditors on three lines, and that it not DRY. It then goes ahead and tells us that to solve this problem, we should monkey-patch an acts_as_audited method into the Active Record::Base object, as follows:
(the book suggests putting this file in /lib/core_ext/active_record_base.rb)
class ActiveRecord::Base
def self.acts_as_audited(audit_log=DEFAULT_AUDIT_LOG)
auditor = Auditor.new(audit_log)
after_create auditor
after_update auditor
after_destroy auditor
end
end
which enables you to write the Account Model class as follows:
class Account < ActiveRecord::Base
acts_as_audited
...
end
Before reading the book, I have already made something similar that adds functionality to multiple Active Record models. The technique I used was to create a Module. To stay with the example, what I have done was similar to:
(I would put this file inside /app/models/auditable.rb)
module Auditable
def self.included(base)
#audit_log = base.audit_log || DEFAULT_AUDIT_LOG #The base class can override it if wanted, by specifying a self.audit_log before including this module
base.after_create audit_after_create
base.after_update audit_after_update
base.after_destroy audit_after_destroy
end
def audit_after_create
#audit_log.created(self.inspect)
end
def audit_after_update
#audit_log.updated(self.inspect)
end
def audit_after_destroy
#audit_log.destroyed(self.inspect)
end
end
Note that this file both replaces the Auditor and the monkey-patched ActiveRecord::Base method. The Account class would then look like:
class Account < ActiveRecord::Base
include Auditable
...
end
Now you've read both the way the book does it, and the way I would have done it in the past. My question: Which version is more sustainable in the long-term? I realize that this is a slightly opinionated question, just like everything about Rails, but to keep it answerable, I basically want to know:
Why would you want to monkey-patch ActiveRecord::Base directly, over creating and including a Module?

I would go for the module for a few reasons.
Its obvious; that is to say, I can quickly find the code that defines this behavior. In acts_as_* I don't know if its from some gem, library code, or defined within this class. There could be implications about it being overridden or piggy-backed in the call-stack.
Its portable. It uses method calls that are commonly defined in libraries that define callbacks. You could conceivably distribute and use this library in non-active-record objects.
It avoids the addition of unnecessary code on the static level. I'm a fan of having less code to manage (less code to break). I like using Ruby's niceties without doing to much to force it to be "nicer" than it already it is.
In a monkey-patch setting you are tying the code to a class or module that could go away and there are scenarios where it would fail silently until your class can't call acts_as_*.
One downfall of the portability argument is the testing argument. In which case I would say you can write your code to protect against portability, or fail early with smart warnings about what will and won't work when used portably.

Related

DelegateClass vs Class Inheritance in Ruby

Can someone please provide some insight as to when to use delegation via DelegateClass (e.g. Seller < DelegateClass(Person)) and when to use class inheritance (e.g. Seller < Person) in ruby?
class Seller < DelegateClass(Person)
def sales
...
end
end
class Seller < Person
def sales
...
end
end
When I was looking over the Ruby on Rails source on Github I found quite a few uses of DelegateClass.
There are a couple of differences that can help provide insight as to which approach to use.
1) You can safely delegate to primitives (e.g. String), but cannot always safely inherit from them
If you're building on top of Hash or String or Fixnum, you're safer using DelegateClass (or another delegator). For more on why, Steve Klabnik's cautioning is a good place to start).
2) DelegateClass makes it easy to “convert” a more general object into a more specific one
This makes it easier to accept an instance of a general object and make it behave in a way that's specific to your implementation:
class Message < DelegateClass(String)
def print
upcase
end
end
# […]
def log(message)
message = Message.new(message) unless message.is_a?(Message)
end
3) A gotcha: DelegateClass subclasses expect an instance of the delegated class as an argument to new
This can make it tricky to “subclass” classes that you're handing to library code. For example, this is a fairly common practice that won't work out of the box with DelegateClass:
class MyLogger < DelegateClass(ActiveSupport::Logger); end
Foo::ThirdParty::Library.configure do |c|
c.logger = MyLogger # no good
end
This doesn't work because our library expects to behave like most loggers and instantiate without arguments. This can be addressed by defining initialize and creating an instance of ActiveSupport::Logger, but probably not the right solution in this case.
delegates model different behaviors of Person based on the context. e.g. the same person could be a seller in one context or a buyer in a different context. Inheritance is more rigid: a Bear and Tiger inherit from Animal, but an instance of Animal would never need to sometimes behave like a Bear and sometimes behave like a Tiger. An instance of a descendent of Animal is either one or the other.

Ruby: Raise error in Module if class method not found

I would like to put some code in module that throws an error if certain method is not defined.
This module relies on the external definition of this method, since this method's implementation is different for all classes. This code would help developers know early that they forgot to implement the method rather than when they tried to use features of the module.
module MyModule
def self.included(klass)
raise "MyModule: please `def my_method` on #{klass}" unless klass.respond_to?(:my_method)
end
end
I can easily raise an error in a module's included definition if a method is not defined, however since most modules are included at the top of a file, it's likely that my required method is defined in the class, but not before my module is included.
class MyClass
include MyModule
def self.my_method
# ...
end
end
This would still raise an error :(
Is it possible to raise an error only if the method truly is not defined in the class definition? Almost need a class.onload callback of sorts. If not, any other ideas for how to mitigate the possibilities that a programmer might include our module without defining this needed method?
Sounds like you want to make use of method_missing and define_method.
If you do use method_missing don't forget to:
call super for unhandled cases.
also implement a respond_to? method
look at this question, plus this and that.
Update:
It sounds the goal is to do static method checking like Java or c++ does. This is not really meaningful in ruby :-(
Since in ruby:
Each instance of an object has its own eigenclass. A given object may have the necessary methods mixed in at runtime. So just because Foo does not have a method at class load time is meaningless.
Frameworks like RoR hooks method_missing and dynamically create methods needed for the database query methods, so the method may exist (or not) when it is needed.
With regards to "class on load": A class definition is really executed. Try this:
class Foo
p "Hi"
end
You will see "Hi" the first and only the first time Foo is used. This is how things like devise hook into do their magic.
class User < ActiveRecord::Base
# **CALL 'devise' method**
devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
# **CALL attr_accessible method**
attr_accessible :email, :password, :password_confirmation
end
So maybe by private convention have developers add a check_class method call to the bottom of the classes in question?
I understand the intent but it seems like fighting the way ruby is designed to work.
As a mostly Java person I appreciate the frustration. Let me guess: repeated cases of code getting pushed to production that had missing methods? :-P
Update2:
wrt onload In ruby barring use of frozen a class get new methods defined all the time. ( Or an instance can get new methods defined just for that instance. ) so checking for a method's nonexistence is only a snapshot check and not as definitive a check as a static language brings to the table. This is ruby's very own Halting problem
How about declaring a method with that name, which just raises an error, to make sure the user redefines the method?
module MyModule
def my_method
raise "Please implement me"
end
end
class MyClass
include MyModule
def my_method
# do something
end
end
Assuming your program requires all files when started and does not use any autoload and the like, you could use something like the following right after everything is required, but before the program actually starts:
classes_to_check = Object.constants.find_all do |const|
klass = Object.const_get(c)
klass.ancestors.include?(MyModule) if klass.kind_of?(Module)
end
classes_to_check.each do |klass|
raise "MyModule: please `def my_method` on #{klass}" \
unless klass.respond_to?(:my_method)
end
However, I personally always use Dogbert's solution.

ruby oo design question should i reopen the class or use extension pattern

so I have an ruby object that i need to create as a pdf and excel row and cvs row
so far I've created a new class with a method to take in the object and do the necessary stuff to produce the pdf , excel , csv
I've been reading Agile Software Development, Principles, Patterns, and Practices and it mentioned the extension method so i was going to do but since this is ruby should i just be reopening the class in the another file and added the methods on there to separate them from the main class
so
file ruby_model.rb
class RubyModel < ActiveRecord::Base
end
then do
ruby_model_pdf.rb
class RubyModel
def to_pdf
end
end
ruby_model_cvs.rb
class RubyModel
def to_csv
end
end
or should i go with with the object extension pattern?
Cheers
You should put your methods in a module and include the module in the class. This way is preferable because it's easier to see where the methods came from (in a backtrace, for example), and it's easier to reuse the methods if it turns out that they can be used in other classes too.
For example:
module Conversions
def to_pdf
end
def to_csv
end
end
class RubyModel
include Conversions
end
It might also be a good idea to put to_pdf and to_csv in different modules, unless it's the case that if you want to mix in one you always want to mix in the other.
This all assumes that the methods don't belong in the class itself, but judging from the names they don't.
If the language feature works fine, then keep it simple and use it.
Design patterns are documented workarounds for cases where the language is not expressive enough. A Ruby example would be Iterator, which is made redundant by blocks and Enumerable.

When to use a module, and when to use a class

I am currently working through the Gregory Brown Ruby Best Practices book. Early on, he is talking about refactoring some functionality from helper methods on a related class, to some methods on module, then had the module extend self.
Hadn't seen that before, after a quick google, found out that extend self on a module lets methods defined on the module see each other, which makes sense.
Now, my question is when would you do something like this
module StyleParser
extend self
def process(text)
...
end
def style_tag?(text)
...
end
end
and then refer to it in tests with
#parser = Prawn::Document::Text::StyleParser
as opposed to something like this?
class StyleParser
def self.process(text)
...
end
def self.style_tag?(text)
...
end
end
is it so that you can use it as a mixin? or are there other reasons I'm not seeing?
A class should be used for functionality that will require instantiation or that needs to keep track of state. A module can be used either as a way to mix functionality into multiple classes, or as a way to provide one-off features that don't need to be instantiated or to keep track of state. A class method could also be used for the latter.
With that in mind, I think the distinction lies in whether or not you really need a class. A class method seems more appropriate when you have an existing class that needs some singleton functionality. If what you're making consists only of singleton methods, it makes more sense to implement it as a module and access it through the module directly.
In this particular case I would probably user neither a class nor a module.
A class is a factory for objects (note the plural). If you don't want to create multiple instances of the class, there is no need for it to exist.
A module is a container for methods, shared among multiple objects. If you don't mix in the module into multiple objects, there is no need for it to exist.
In this case, it looks like you just want an object. So use one:
def (StyleParser = Object.new).process(text)
...
end
def StyleParser.style_tag?(text)
...
end
Or alternatively:
class << (StyleParser = Object.new)
def process(text)
...
end
def style_tag?(text)
...
end
end
But as #Azeem already wrote: for a proper decision, you need more context. I am not familiar enough with the internals of Prawn to know why Gregory made that particular decision.
If it's something you want to instantiate, use a class. The rest of your question needs more context to make sense.

Whats a good ruby idiom for breaking up a large class into modules?

I have a large class with lots of methods and it's starting to get a bit unorganized and hard to navigate. I'd like to break it up into modules, where each module is a collection of class and instance methods. Perhaps something like this:
UPDATE: I've now realized that this is a pretty poor example. You probably wouldn't want to move validations or attributes out of the core class.
class Large
include Validations
include Attributes
include BusinessLogic
include Callbacks
end
After reading Yehuda's post about Better Ruby Idioms, I'm curious how others are tackling this problem. Here's the two methods I can think of.
First Method
module Foo
module Validations
module ClassMethods
def bar
"bar"
end
end
module InstanceMethods
def baz
"baz"
end
end
end
class Large
extend Validations::ClassMethods
include Validations::InstanceMethods
end
end
Second Method
module Foo
module Validations
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def bar
"bar"
end
end
def baz
"baz"
end
end
class Base
include Validations
end
end
My questions are:
Is there a better way to do this?
How do you get a one-liner module mixin for a set of class/instance methods with the least amount of magic?
How do you namespace these modules to the base class without namespacing the class itself?
How do you organize these files?
Breaking a class into modules, while tempting (because it's so easy in Ruby), is rarely the right answer. I usually regard the temptation to break out modules as the code's way of telling me it wants to be split into more tightly-focussed classes. A class that's so big you want to break it into multiple files is pretty much guaranteed to be violating the Single Responsibility Principle.
EDIT: To elaborate a bit on why breaking code into modules is a bad idea: it's confusing to the reader/maintainer. A class should represent a single tightly-focussed concept. It's bad enough when you have to scroll hundreds of lines to find the definition of an instance method used at the other end of a long class file. It's even worse when you come across an instance method call and have to go looking in another file for it.
After doing what Avdi said, these are the things I would do before putting anything into a module:
Whether this module can or will be used in any other class?
Would it make sense to extract the functionality of these modules into a different or base class?
If the answer for 1 is no and 2 is yes then IMHO that indicates to better have a class rather a module.
Also, I think putting attributes in a module is conceptually wrong because classes never share their attributes or instance variables or in other words their internal state with any other class. The attributes of a class belongs to that class only.
Business logics do definitely belong to the class itself and if the business logic of class A has some common responsibilities with class C then that needs to be extracted into a base class to make it clear instead of just putting it into a module.
The standard idiom seems to be
foo.rb
foo/base.rb
foo/validations.rb
foo/network.rb
foo/bar.rb
and foo.rb would be something like
class Foo
include Foo::Base
include Foo::Validations
include Foo::Network
include Foo::Bar
end
This is the standard idiom, and it works fairly well for letting you break things up. Don't do class methods vs instance methods. Those are generally pretty arbitrary distinctions, and you're better off putting code that deals with similar subjects together. That will minimize how many files you have to touch for any given change.
BEWARE: Rails can get confused by nesting models like this, at least if everything were classes. I think it'll do better with all the nested files just being modules, but you'll have to see. I'm still suggesting this because it's the normal idiom used by the Ruby community, but you may have to avoid having both a foo.rb and a foo/ directory amongst your Rails models (if that's the kind of class you're talking about).
Although including different modules will work, it is generally more troublesome than simply reopening the class in multiple places.
There is a (very simple) gem that you can use to makes this as pretty as can be: concerned_with
Example (from the readme)
# app/models/user.rb
class User < ActiveRecord::Base
concerned_with :validations,
:authentication
end
# app/models/user/validations.rb
class User < ActiveRecord::Base
validates_presence_of :name
end
#app/models/user/authentication.rb
class User < ActiveRecord::Base
def self.authenticate(name, password)
find_by_name_and_password(name, password)
end
end
I tend to use Ruby's duck typing approach to interfaces, which basically allows you to send any message to any object, which then evaluates what to do with it.
This approach allows me to stick to the same pattern Avdi mentions, keeping classes small and concise- only ever being responsible for one thing.
The great thing about Ruby is that you can delegate responsibilities to other concise classes, without muddling any of the logic together. For example:
class Dog
def initialize(name)
#name = name
end
def bark
"woof"
end
def fetch(object)
"here's that #{object}"
end
def sit
"sitting down"
end
private
attr_accessor :name
end
Here we have my dog class that has loads of dog related methods. They're all specific to dog, so could happily reside here. However, there would be a problem if these methods got a bit complex, calling other methods or perhaps this dog learns a bunch of new tricks!? So I could separate these out into their own classes and then delegate responsibility to those, like so:
class Tricks
def initialize(name)
#name = name
end
def fetch(object)
"here's that #{object}"
end
def sit
"sitting down"
end
def come_when_called(my_name)
"I'm coming" if my_name == name
end
def put_toy_away(object)
"#{fetch(object)}, I'll put it away"
end
private
attr_reader :name
end
class Dog
def initialize(name)
#name = name
end
delegate :sit, :fetch, :come_when_called, :put_away_toy, to: :tricks_klass
def bark
"woof"
end
private
attr_accessor :name
def tricks_klass
#tricks_klass ||= Tricks.new(name)
end
end
So now, that Dog class really starts to behave like an interface to dog-related behaviors, whilst these tricks are no longer coupled to it. This'll make testing easier by being able to instantiate a Tricks object and test it more generically, without the need for a Dog (because they don't always listen).
Now, we could have a Cat class that delegates responsibility to this Tricks class as well- although, that'd be one smart Cat!
You could also now use the Tricks class on its own- that's the power encapsulating single behavior its own class. You could even separate these behaviors even further- but only you as the developer know if that's worth while!

Resources