ayoros February 2016

Rails customize class Gem

I reopened a gem class in my rails app, everything seems to be ok, everything runs nicely but after a few minutes, it seems like my app forgot all the modifications:

config/initializers/rapidfire_custom.rb

::Rapidfire::Survey.class_eval do

  belongs_to :campaign, class_name: '::Campaign', inverse_of: :survey

  before_create :default_active
  before_validation :default_status, :default_name

  STATUS = ['DRAFT', 'PUBLISHED']
  validates_inclusion_of :status, in: STATUS
  validates :name, presence: true

  scope :from_company, -> (id) { where(company_id: id) }
  scope :template, -> { where(campaign_id: nil) }
  scope :published, -> { where(status: 'PUBLISHED') }

  def default_active
    self.active ||= true
  end

  def default_status
    self.status ||= 'DRAFT'
  end

  def self.all_status
    STATUS
  end

  def default_name
    if self.campaign
      self.name = 'Survey'
    end
  end

end

The error:

undefined method `template' for #<Rapidfire::Survey::ActiveRecord_AssociationRelation:0x007fc762215ad0>

It happens only on development, i'm using puma:

config/puma.rb

workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['MAX_THREADS'] || 5)
threads threads_count, threads_count

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3000
environment ENV['RACK_ENV'] || 'development'

if ENV['RACK_ENV'].nil? || ENV['RACK_ENV'] == 'development'
  ssl_bind 'my_website.dev', '3000', { key: 'ssl/device.key', cert: 'ssl/device.crt' }
end

on_worker_boot do
  ActiveRecord::Base.establish_connection
  $redis.client.reconnect
end

I don't know what's going on, any idea ?

Thanks

Answers


max February 2016

I'm guessing that when ActiveRecord instantiates Rapidfire::Survey records it loads the class from the gem - which nullifies the changes you have done with class eval in the initializer.

Monkey-patching objects that does not belong to you should only really be done if you need to override a library method and there is no better way.

You also need to consider when and where class eval happens - initializers are run when the rails app is loading while model classes are lazy loaded when ActiveRecord needs them. So using an initializer to configure a model is not a very good idea.

Using inheritance is the correct thing to here - you're creating your own domain object.

Post Status

Asked in February 2016
Viewed 2,180 times
Voted 11
Answered 1 times

Search




Leave an answer