0

I'm creating a gem on Rails 5.

Let's say I have SomeModel with a hello method, which I use within myengine:

# app/models/myengine/someModel.rb
module Myengine
  class SomeModel < ApplicationRecord
    def self.hello
      puts 'hello world'
    end
  end
end

I would like to remove hello method from default application and store it into a gem so I can plug it in only if I need to.

I don't know neither what to write to extend the model nor where to place that file.

I tried to fo through the Rails guidelines, but they are way too complicated! I got lost after several tries. I don't need Single Table Inheritance, I need to extend that specific model.

Tried already this answer which seems not quite right, and this one which doesn't unfortunately say much.

Any idea?

Community
  • 1
  • 1
a.barbieri
  • 1,810
  • 22
  • 47
  • maybe you should just write module with `hello` method and extend model within application not gem itself? – Aleksey Sep 23 '16 at 13:36
  • what do you mean by "write module with `hello`" and by "extend model within application not gem itself"? I need a gem as this is part of a wider thing I'm doing which has to be replicated easily on several Rails applications. – a.barbieri Sep 23 '16 at 13:39
  • Hey @Aleksey, I think I nailed it. – a.barbieri Sep 23 '16 at 16:21

1 Answers1

1

Ok, after digging the web and crashing my head against the wall I've finally come to a conclusion.

Suppose you want to extend the features of SomeModel in your default application engine myengine:

# app/models/myengine/some_model.rb
module Myengine
  class SomeModel < ApplicationRecord
    # some code
  end
end

You can either do it in your config/intializers folder or in the lib/myplugin folder. I show both, the first on the concern way, the second using the self way.


The Concern way

In your gem you can extend SomeModel adding the hello method using Concern:

# myplugin/config/initializers/some_model_extension.rb
module Myplugin::SomeModelExtension

  extend ActiveSupport::Concern

  class_methods do
    def hello
        return "Hello world!"
    end
  end

end

class Myengine::SomeModel < ActiveRecord::Base
    include Myplugin::SomeModelExtension
end

You can update ClassMethods, but the same goes for InstanceMethods (if you don't know the difference between instance methods and class methods you should read this).

If you want to add associations like has_many or belongs_to you can use included do as this guy did.


The self way

This works as well

# myplugin/lib/myplugin/some_model_extension.rb
module SomeModelExtension

  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods
    def hello
      return 'Hello world'
    end
  end

end

class Myengine::SomeModel < ActiveRecord::Base
    include SomeModelExtension
end
# myplugin/lib/myplugin.rb
require 'myplugin/some_model_extension'

If you want to read more, check Rails Guidelines.

Also it's worth checking this awesome answer.


Community
  • 1
  • 1
a.barbieri
  • 1,810
  • 22
  • 47
  • Seems like you did a great job! But why you don't use `ActiveSupport::Concern`? – Aleksey Sep 23 '16 at 16:37
  • Yep, I've gone that way as well. I'm still improving the answer as it's not quite right yet. But almost there. I have problems with association... that doesn't work. – a.barbieri Sep 23 '16 at 16:47
  • Ok, the concern way it's fine. The second way is ok, but couldn't understand how to make associations work. It doesn't really matter as far as I can use *concern* ;-) – a.barbieri Sep 23 '16 at 17:02
  • you should use it! =) – Aleksey Sep 23 '16 at 17:21