Where to Reopen a Class in Ror

Where to reopen a class in RoR

The most logical place is probably in a file in the config/initializers directory. Any *.rb file you put in here will be automatically executed when rails boots. If you want, you could put them in a sub folder, so you could do something like config/initializers/extensions/*.rb.

Reopen Impression Class from Impressionist Gem in Rails 4

If you're overriding a class provided by a gem, you will need to manually require your version to get your changes included. This is usually done in an initializer.

ruby modules and classes same name in structure

Bar can't be a module and a class, they are different things.

Change bar.rb to module Bar or change other_bar.rb to class Bar.

Whichever it is, it has to be consistent. You can't change one to the other. The question is which should it be? If Bar is a container for other classes and only has a few global singleton methods? Then it's a module. But if it can be instantiated, then it's a class.

And yes, you can nest classes. This is totally acceptable:

class Bar
class OtherBar
puts "running module Bar with class OtherBar"
end
end

Bar::OtherBar.new # yay!

Modules and Classes can be nested inside either other in any way you see fit.


Edit with some commented examples to help clear this all up:

module Foo

# Foo::A
class A
# simple namespaced class
end

# Foo::B, inherits from Foo::A
class B < A
# inherting from a class in the same namespace
end

# modify Foo::B
class B
# When modifying an existing class you don't need to define the superclass
# again. It will raise an error if you reopen a class and define a different
# superclass. But leaving it off is fine.
end

# nested module Foo::Inner
module Inner

# Foo::Inner::C
class C
# simple more deeply namespaced class
end

# Foo::Inner::D, inherits from Foo::A
class D < A
# inherits from a class in a parent namespace

# works because ruby looks upward in the nesting chain to find missing constants.
end

# Foo::Inner::Foo
class Foo
# simple nested class with the same name as something in a parent namespace

# This is a totally different Foo, because it's in a different namespace
end

# Foo::Inner::E, inherits from Foo::Inner::Foo
class E < Foo
# class inhereting from another class in the same namespace

# Foo::Inner::Foo is "closer" than the global Foo, so that gets found as the superclass
end

# Foo::Inner::F, which mixes in the gloabl module Foo
class F
# the :: constant prefix says to start looking in the global namespace
# so here we include the top level module Foo, and not the "closer" in namespace Foo::Inner::Foo
include ::Foo

# This is an error. This attempts to include the class Foo::Inner::Foo since thats the closest by namespace
# thing that matches the constant Foo. (you can't include classes, only modules)
# You need the :: prefix to grab the global Foo module
include Foo
end

end
end

# Z decalred in the global namespace, which inherits from the deeply nested class Foo::Inner::C
class Z < Foo::Inner::C
# Any class anywhere can inherit from any other class in any namespace.
# Just drill in!
end

# the following 2 declarations at this point would be identical

# This defines a class deep with in a namespace
class Foo::Inner::Foo::Bar < Foo::A
end

# same as above, but reopens each namespace
module Foo
module Inner
class Foo
class Bar < ::Foo::A
end
end
end
end

Rails 3 - Extending a model that exists in a gem or plugin

Ruby allows the developer to "update" any object, at anytime.

That means that after Model is loaded by RefineryCMS you can just reopen the class and update it:

class Model
def new_method(value)
...
end

def existing_method(*args)
...
super # refer to the ovewriten method
end
end

In your case RafineryCMS is an RoR app, that means while loading the server the ruby code is loaded first for the rails framework, then for the RafineryCMS gem/plugin and after all for your custom libraries (eg: lib folder).

The important point here is the loading order of the code, modification should be loaded after the genuine class code.

That is in your lib or initializers (not really a good place but it works) you should put your custome methods for the Model class.

EDIT: I was reading your question again, and I have to mention, that you are wrong, you actually can change a class from a gem or plugin.
ruby load every object in the same scope and all objects are accessible to be overwritten.

In development environment, RoR, reloads all classes (except if cache_classes = false) on every request. It is possible, that after the first request, the gem is reloaded and your changes are lost. Take care to reload your libraries after for every request (only in developement env)

PS: include & class_eval would work too, the important thing is too overwrite a previously loaded class

Access ActionView::Helpers::DateHelper from class defined in /lib directory

Ruby's include is adding ActionView::Helpers::DateHelper to your class instance.

But your method is a class method (self.send_email). So, you can replace include with extend, and call it with self , like this:

class EmailHelper
extend ActionView::Helpers::DateHelper

def self.send_email(email_name, record)
# Figure out which email to send and send it
time = self.time_ago_in_words(Time.current + 7.days)

# Do some more stuff
end
end

That's the difference between include and extend.

Or...

you can call ApplicationController.helpers, like this:

class EmailHelper

def self.send_email(email_name, record)
# Figure out which email to send and send it
time = ApplicationController.helpers.time_ago_in_words(Time.current + 7.days)

# Do some more stuff
end
end

Ruby on rails - access model data within another model

Model-ception!!


Objects

The best way to describe the issue you have is to outline that Ruby (& Rails by virtue of being built on top of the Ruby language) is object-orientated.

Contrary to popular belief, object-oriented is more than just a buzzword - it means that every element of your application should be constructed around objects. Objects are essentially "variables" which have a collection of attributes & other data attached to them:

Sample Image

In Rails, an object is created as an instance of a model (class)


Fix

When you're calling OtherModel.name, you're not initializing an instance of the relevant class, hence meaning you will not be able to display any of the attributes it has

To ensure this issue can be remedied, you need to ensure you load an instance of your OtherModel object, to ensure you're able to call the relevant data:

#app/models/my_model.rb
Class MyModel < ActiveRecord::Base
def to_param
return OtherModel.first.name #-> returns first instance of `OtherModel` & then displays "name"
end
end

Associations

A better option is to harness ActiveRecord Associations:

#app/models/my_model.rb
Class MyModel < ActiveRecord::Base
has_many :other_models
end

#app/models/other_model.rb
Class OtherModel < ActiveRecord::Base
belongs_to :my_model
end

This means you'll be able to call the following:

@my_model = MyModel.find 1
@my_model.other_models.each do |other|
puts other.name
end

See how the ActiveRecord associations creates an instance of the associated model? This allows you to call it from the instance of your "parent" model without having to re-initialize it

--

Delegate

You may also be able to use the delegate method depending on your association setup:

#app/models/my_model.rb
Class MyModel < ActiveRecord::Base
belongs_to :other_model
delegate :name, to: :other_model, prefix: true
end

#app/models/other_model.rb
Class OtherModel < ActiveRecord::Base
has_many :my_models
end

This will allow you to call:

@my_model = MyModel.find 1
@my_model.other_model_name

It must be noted the delegate method only works with belongs_to relationships

How to properly monkey patch the Numeric class on RoR?

As max commented, you can use Rails initializers folder for monkey patching the libraries.

I would suggest creating a new folder core_extensions within config/initializers/ and group patches related to the same module/class in a separate file and place the include at the last line.

## File path: config/initializers/core_extensions/numeric.rb

# frozen_string_literal: true

module CoreExtensions
module Numeric
def percent_of(number)
to_f / number * 100.0
end
end
end

Numeric.include CoreExtensions::Numeric

I need to modify the code of a third-party gem, where and how to do?

Ruby has open classes, to you should always tend toward reopening and redefining the method(s) you need to, so reopening SessionsController and overriding the create method would be the way to go.

Editing the gem directly puts a maintenance burden on you and everyone else that has to touch the code in the future. Eventually someone is going to forget and update that gem.

Where should I place my own module within rails application?

Rails < 5

Before Rails 5, the place to put reusable code such as this is in the lib directory. However you do not need to require anything as lib is already in the load path and it's contents will be loaded during initialization.

If you need to extend an existing class, you define your module first and then include it by sending it as a message to the class you wish to extend, e.g.

module MyExtensions
def self.included base
base.instance_eval do
def my_new_method

end
end
end
end

ActiveRecord::Base.send :include, MyExtensions


Related Topics



Leave a reply



Submit