3

I'm trying to solve a strange issue. I'm extending ActiveRecord using a module.

module StringyAssociationIds

  def stringy_ids(association)
    define_method("stringy_#{association}_ids=") do |comma_seperated_ids|
      self.send("#{association}_ids=", comma_seperated_ids.to_s.split(","))
    end

    define_method("stringy_#{association}_ids") do
      send("#{association}_ids").join(",")
    end
  end

end

ActiveRecord::Base.extend(StringyAssociationIds) 

I have a class "Gate" where I have an association.

class Gate < ActiveRecord::Base
  include Productable
  stringy_ids :product
end

The association is defined with a join table:

module Productable
  extend ActiveSupport::Concern

  included do
    has_many :productable_products, as: :productable
    has_many :products, through: :productable_products
  end

end

When I try to create a new Gate I have an error:

undefined method `stringy_ids' for #<Class:0x007f91e12bb7e8>

Where is my fault?

Edit: I try also to add an extension inside the lib directory (autoloaded by application.rb)

module ActiveRecordExtension

  extend ActiveSupport::Concern

  def stringy_ids(association)
    define_method("stringy_#{association}_ids=") do |comma_seperated_ids|
      self.send("#{association}_ids=", comma_seperated_ids.to_s.split(","))
    end

    define_method("stringy_#{association}_ids") do
      send("#{association}_ids").join(",")
    end
  end

end

# include the extension 
ActiveRecord::Base.send(:include, ActiveRecordExtension)

I try also in console:

ActiveRecordExtension.instance_methods
 => [:stringy_ids]

So my extension is loaded...

Roberto Pezzali
  • 2,484
  • 2
  • 27
  • 56
  • It looks like `ActiveRecord::Base` is not extended with your `StringyAssociationIds` module *before* `Gate` class definition. `string_ids` is invoked immediately after source parsed, before any instantiation. Either make sure proper loading order, ie `Gate` processed afterwards, or move `stringy_ids` into initializer. Btw. why are you polluting Activerecord and not Gate class directly ? – joanbm Dec 26 '15 at 17:35

2 Answers2

3

Your class method stringy_ids is defined on ActiveRecord::Base, not Gate. Unlike instance methods, class methods are not inherited because the singleton class of Gate is not a subclass of the singleton class of ActiveRecord::Base.

sawa
  • 165,429
  • 45
  • 277
  • 381
  • I copied the code inside my class and I receive the same error. I'm following this [gist](https://gist.github.com/smoil/5061616) – Roberto Pezzali Dec 26 '15 at 15:51
  • I try also in another way, following [this so answer](http://stackoverflow.com/questions/2328984/rails-extending-activerecordbase). Doesn't work. – Roberto Pezzali Dec 26 '15 at 15:59
0

StringyAssociationIds is not extended.
Actually, ActiveRecord::Base.extend(StringyAssociationIds) does not run. Move this code in config/initializer

Jaehyun Shin
  • 1,562
  • 14
  • 25
  • I already try to move it. My lib directory is autoloaded on application start. – Roberto Pezzali Dec 26 '15 at 16:03
  • Do you mean your lib directory is added to `config.autoload_pathes`? – Jaehyun Shin Dec 26 '15 at 16:17
  • When you add in autoload_path it is not actually run at start. It run when module is called firsttime. I think systme does not read ActiveRecord::Base.send(:include, ActiveRecordExtension) or ActiveRecord::Base.extend(StringyAssociationIds) line. try in console execute 'ActiveRecord::Base.extend(StringyAssociationIds)' and call Gate – Jaehyun Shin Dec 26 '15 at 16:57
  • I try to move in initializer... in console ActiveRecord::Base.send(:include, ActiveRecordExtension) ActiveRecordExtension.instance_methods => [:stringy_ids] But Gate.new return me error "undefined method" – Roberto Pezzali Dec 26 '15 at 17:05
  • not 'include' maybe 'extend' 'stringy_ids=' is class method – Jaehyun Shin Dec 26 '15 at 17:21