How does one add a callback for a gem's model? - ruby-on-rails

I have my own app. And I use some gem. This gem has, for example, User model.
How I can add my custom callback (after_save) for User model (which defined in gem without and callback for this model)?

You might be able to do this using an initializer, monkey-patching the User class in the gem:
# config/initializers/some_gem.rb
module SomeGem
class User
after_save :my_callback
private
def my_callback
...
end
end
end

You can accomplish this by monkey-patching the User class in an initializer as already described in this answer.
Alternatively, you can use the rails-observers gem to keep your logic outside outside third party classes:
Observer classes respond to life cycle callbacks to implement trigger-like behavior outside the original class. This is a great way to reduce the clutter that normally comes when the model class is burdened with functionality that doesn't pertain to the core responsibility of the class

Related

Rspec test of private model method in rails app

I have a private model method in my rails app that is so vital to quality of life as we know it that I want to test it using rspec so that it squawks if future tampering changes how it works.
class MyModel < ApplicationRecord
belongs_to something
has_many somethings
after_create :my_vital_method
validates :stuff
private
def my_vital_method
#do stuff
end
end
When I try calling the method in an rspec test I get the following error message:
NoMethodError: undefined method `my_vital_method' for #< Class:......>
Question: How do I call a private model method in rspec?
By definition, you are not allowed to call private methods from outside of the class because they are private.
Fortunately for you, you can do what you want if you use object.send(:my_vital_method) which skips the testing for method call restrictions.
Now, the bigger issue is that you really are making your object more brittle, because calling from outside like that may need implementation details that will get out of sync with the class over time. You are effectively increasing the Object API.
Finally, if you are trying to prevent tampering, then you are tilting at windmills -- you can't in Ruby because I can just trivially redefine your method and ensure that if my new method is called from your anti-tamper checking code, I call the original version, else I do my nefarious stuff.
Good luck.
If your private method needs testing it probably should be a public method of another class. If you find the name of this class define its purpose and then create the method signature you want you would end up with something like
def my_vital_method
MyVitalClass.new.do_stuff
end
and now you can write a spec for do_stuff.

What are before_create, validates_presence_of, has_many etc?

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.

How to use redirect_to method inside of custom class

This one is very straightforward. with my controllers, i am using special custom class stored in concerns. I would like this class to be able to send user, well, places. In order to do this i need path helpers, which i got with this:
include Rails.application.routes.url_helpers
but this approach also requires redirect_to method. what module should i include inside my class to be able to use it? or maybe some class it can inherit after? (but module would much more elegent solution).
In Rails 2.3, the redirect_to that you want is a protected method in ActionController::Base, so you'd have to make a subclass of that class. In the most recent Rails (currently 4.0.2), it's a public method in ActionController::Redirecting, so you could include that module.
The commenters on the original question are right, though: it doesn't sound like a good idea to do a redirect from an object that's not really a controller.

How to Implement Mongoid callbacks in a Module

I'm trying to implement a model auditor that looks for changes to the Mongo. Originally, I tried to make a base class that my models inherit from, but I found out that's not possible.
I'm adding a module to a model that relies on Mongoid. The module contains after_create, after_update, and after_destroy callbacks. And that's the problem... In order to get the callbacks to work as if they are class-level methods, I have to do something this.
module Auditor
def self.after_create
#after create code
end
end
However, I this will override any after create calls inside my model.
Is there a way I can modify my Auditor module's after_create method to accept what the model wants to run callbacks on?

Is there a way to remove method calls in Rails?

I'd like to catch and remove method calls in my Rails models in certain cases.
I'd like something like the remove_method, but that removes method calls.
For example, if I have a before_save callback in a model, I may want to catch it using a module that's extended into the class, and remove or prevent the before_save from firing.
Is this possible?
Thanks.
Edit:
The pervious answer I posted does not work - not sure if it ever did, but I vaguely recall using in the past. To skip callbacks, in the context of a subclass, for example, you should use skip_callback. Example of the usage:
skip_callback :save, :before, :callback_method_name
Or if you want to skip callbacks under a for a particular condition:
skip_callback :save, :before, :callback_method_name, if: :some_condition_true?
There is also a reset_callbacks method that takes the callback type as a parameter. For example, reset_callbacks :save. The callbacks can be accessed via the class methods, _save_callbacks, _create_callbacks, etc. I would use caution when using reset_callbacks since it appears that Rails itself is defining callbacks for associations, namely, :before_save_collection_association.
If you're talking about just regular Ruby objects, you can override methods in subclasses. Just define a method with the same name as the superclass. You can also override base class methods in a subclass by including a module which defines the same instance methods as the base class.
Have you tried clearing before_save like this:
before_save ->{}

Resources