run script after initialize

hi there!!

I'm just trying to run a script that adds certain methods to all
ActiveRecord::Base descendants, but what happens is that it seems that
all models are loaded after the application runs

ActiveRecord::Base.send(:descendants).each do |subclass|
#do stuff
end

ActiveRecord::Base.send(:descendants) and
ActiveRecord::Base.send(:subclasses) is allways empty [].

I've tried it on config/environment.rb and config/application.rb with no
success, can someone tell me what i can do about it?

Thanks!

hi there!!

I'm just trying to run a script that adds certain methods to all
ActiveRecord::Base descendants, but what happens is that it seems that
all models are loaded after the application runs

ActiveRecord::Base.send(:descendants).each do |subclass|
#do stuff
end

ActiveRecord::Base.send(:descendants) and
ActiveRecord::Base.send(:subclasses) is allways empty [].

I've tried it on config/environment.rb and config/application.rb with no
success, can someone tell me what i can do about it?

You could just reopen ActiveRecord::Base. Create a new initializer (a ruby file in config/initializers) with:

class ActiveRecord::Base
  def new_method
    # do stuff
  end
end

Does that help?
Jeremy Walker
http://www.ihid.co.uk

Jeremy Walker wrote in post #1059748:

ActiveRecord::Base.send(:descendants) and
ActiveRecord::Base.send(:subclasses) is allways empty [].

I've tried it on config/environment.rb and config/application.rb with no
success, can someone tell me what i can do about it?

You could just reopen ActiveRecord::Base. Create a new initializer (a
ruby file in config/initializers) with:

class ActiveRecord::Base
  def new_method
    # do stuff
  end
end

Does that help?
Jeremy Walker
http://www.ihid.co.uk

Not in my case. What I want to do is define different method names
depending on its relation, for example:

ActiveRecord::Base.send(:descendants).each do |subclass|
        subclass.reflect_on_all_associations.each do |association|
          macro = association.macro #:has_one, :has_many...
          subclass.send(:define_method, "#{association.name}_tokens") do
            read_attribute(__method__[0..-8])
          end
       end
end

tryied something different, but no success again:

Dir[Rails.root.join('app/models/*.rb').to_s].each do |filename|
        require filename #Connection not stablished...
        klass = File.basename(filename).sub(/.rb$/,
'').classify.safe_constantize
        next unless klass.nil? ||
klass.ancestors.include?(ActiveRecord::Base)
        klass.reflect_on_all_associations.each do |association|
          klass.send(:define_method, "#{association.name.to_s}_tokens")
do
            read_attribute(__method__)
          end
        end
      end

It raises connection not stablished.

Guillem Vidal wrote in post #1059754:

Jeremy Walker wrote in post #1059748:

ActiveRecord::Base.send(:descendants) and

ActiveRecord::Base.send(:subclasses) is allways empty [].

I’ve tried it on config/environment.rb and config/application.rb with no

success, can someone tell me what i can do about it?

You could just reopen ActiveRecord::Base. Create a new initializer (a

ruby file in config/initializers) with:

class ActiveRecord::Base

def new_method

# do stuff

end

end

Does that help?

Jeremy Walker

http://www.ihid.co.uk

Not in my case. What I want to do is define different method names

depending on its relation, for example:

ActiveRecord::Base.send(:descendants).each do |subclass|

subclass.reflect_on_all_associations.each do |association|

      macro = association.macro #:has_one, :has_many...

      subclass.send(:define_method, "#{[association.name](http://association.name)}_tokens") do

        read_attribute(__method__[0..-8])

      end

   end

end

OK, so two more suggestions:

  1. Use an after_initialize block in your config (http://guides.rubyonrails.org/configuring.html#rails-general-configuration) to call your method_creation code.

  2. Re-open the class (as per my prev suggestion) but write a create_association_tokens method that contains the code to define your reflected methods, and use ActiveRecord::Base’s after_initialize method to call that method on an object, thus creating your methods on an object-by-object basis, rather than for the class.

I’m intrigued by the point of all this?

Well, I'd create a file and put it in /lib and include/initialize that file in the config.ru file before the actual app initialization (run YourApp::Application).

Jeremy Walker wrote in post #1059759:

> You could just reopen ActiveRecord::Base. Create a new initializer (a
> http://www.ihid.co.uk
      end
end

OK, so two more suggestions:
1) Use an after_initialize block in your config (
http://guides.rubyonrails.org/configuring.html#rails-general-configuration)
to call your method_creation code.
2) Re-open the class (as per my prev suggestion) but write a
create_association_tokens method that contains the code to define your
reflected methods, and use ActiveRecord::Base's after_initialize method
to
call that method on an object, thus creating your methods on an
object-by-object basis, rather than for the class.

I'm intrigued by the point of all this?

Sorry about the delay, I couldn't access to a computer since now :(.

Done it, but it raises me an error because i have a attr_writer, i need
to initialize the method.

module MyModule
def self.included(base)
  base.send(:extend, InstanceMethods)
  base.send(:after_initialize, :set_reader_writer_tokens)
end

module InstanceMethods
  def set_reader_writer_tokens
    class.reflect_on_all_associations.each do |association|
      class.send(:define_method,"#{association.name.to_s}_tokens") do
        attribute(__method__)
      end
      self.class.send(:define_method,
"#{association.name.to_s}_tokens=") do |value|
        write_attribute(__method__, self.another_custom_method)
      end
    end
  end
end

ActiveRecord::Base.send(:include, MyModule)

Loading development environment (Rails 3.2.2)
class OptionType < ActiveRecord::Base
belongs_to :type
end

OptionType.new(:type_tokens => "ba,b")
raises an unknown attribute :type_tokens.

But if I first initialize the record withouth accessing to the
attribute:

OptionType.new

=> #<OptionType ...>

OptionType.new(:type_tokens => "ba,b")

=> #<OptionType id: nil, name: nil, presentation: nil, created_at: nil,
updated_at: nil>

Then I can done it. The problem is that I need to set up that attribute
before the initialitzation of the class.

Is a very good approach, but still not enogh for a ruby on rails
application.

Maybe it can be done using method_missing... but I'm a little bit scared
of overwriting activerecord method_missing, also it's not clear.

Rodrigo Vieira wrote in post #1059873:

Well, I'd create a file and put it in /lib and include/initialize that
file in the config.ru file before the actual app initialization (run
YourApp::Application).

That worked! The problem is that this is only working when rails app
starts, not on rake tasks or test/units.

But from now on, what I need for my application is ok.

Just to know... Is it possible to do add those methods on the entire
application? (not only on the middleware)

If the config.ru trick doesn't work for you, you should try the same but only initializing the file in config/boot.rb, instead. This should work for sure.