Search code examples
ruby-on-railsrubyrubygemsloadingsubdirectory

Ruby on Rails: Add subfolder in app directory with files specific to models


I am writing a gem which will handle all kind of notifications for a model (sms, mobile and browser notifications)

in rails project under app directory created new folder 'notifiers' which contain files like

app/notifiers/user_notifier.rb

class UserNotifier < ApplicationNotifier
  def send_reminder
   {
     type: 'sms',
     content: 'hi everyone',
     recipients: [12134343,2342322,3434343]
   }
  end
end

this user_notifier file should be against User model. means that this method send_reminder should be available to instance/object of User

User.last.send_reminder So, issue is

  • how to make files of notifiers folder to model specific (user.rb model file has user_notifier.rb file in notifiers folder)
  • how this file user_notifier.rb methods would be available to user model

This is possible with concerns and namespaces but this would create messy code


Solution

  • Thanks to Léonard, he posted the solution but while writing the gem we need to handle these configuration from gem. Because when someone use our gem he/she don't have to write any configuration related logic in application_record.rb manually.

    posting it just to ensure that in future may it helpful for someone else.

    what i did to tackle this issue (to attach gem with a model we add act_as_notifier in model with which we want it to be configured)

    • In model_config.rb class of notifier gem
    • Have @model_class & find corresponding notifier class
    • Add attr_accessor in notifier class and initialize it with model object
    • Also define custom getter and setters notifier attribute
    #rails_notifier/model_config.rb
        def initialize(model_class)
          @model_class = model_class
          
          # get model corresponding notifier class
          # for User model class, there would UserNotifier class
          # under notifiers folder of app directory
          # getting notitifer class name
          notifier_class = "#{@model_class.name}Notifier"
          
          # Notifier class attribute set later set with model object
          attribute_name = @model_class.name.underscore
          
          # register a `notifier` method in model class
          # 'method_name' is a method of notifier class
          # and options hash contain sender
          @model_class.class_eval do
            define_method(:notifier) do |method_name, options|
              # create notifier class object
              notifier_ = notifier_class.constantize.new
    
              # define setter for notifier attribute
              notifier_.send(:define_singleton_method, "#{attribute_name}=".to_sym) do |value|
                instance_variable_set("@" + attribute_name.to_s, value)
              end
    
              # define getter for notifier attribute
              notifier_.send(:define_singleton_method, attribute_name.to_sym) do
                instance_variable_get("@" + attribute_name.to_s)
              end
    
              # self point to the object of model
              # e.g User.last.notifier(:send_reminder), slef = User.last
              # set notifier attribute with model object
              notifier_.send("#{attribute_name}=".to_sym, self)
              notifier_hash = notifier_.send(method_name)
              RailsNotifier.notify(notifier_hash) if notifier_hash.present?
            end
          end
        end