run script after initialize

67 views
Skip to first unread message

Guillem Vidal

unread,
May 6, 2012, 3:22:25 PM5/6/12
to rubyonra...@googlegroups.com
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!

--
Posted via http://www.ruby-forum.com/.

Jeremy Walker

unread,
May 6, 2012, 3:50:02 PM5/6/12
to rubyonra...@googlegroups.com
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

> Thanks!
>
> --
> Posted via http://www.ruby-forum.com/.
>
> --
> You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
> To post to this group, send email to rubyonra...@googlegroups.com.
> To unsubscribe from this group, send email to rubyonrails-ta...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
>

Guillem Vidal

unread,
May 6, 2012, 5:13:04 PM5/6/12
to rubyonra...@googlegroups.com
Jeremy Walker wrote in post #1059748:
> On 6 May 2012, at 20:22, Guillem Vidal <li...@ruby-forum.com> wrote:
>
>> 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

Guillem Vidal

unread,
May 6, 2012, 5:54:39 PM5/6/12
to rubyonra...@googlegroups.com
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

unread,
May 6, 2012, 6:04:07 PM5/6/12
to rubyonra...@googlegroups.com
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?
 

Rodrigo Vieira

unread,
May 6, 2012, 6:59:01 PM5/6/12
to rubyonra...@googlegroups.com
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).

Guillem Vidal

unread,
May 7, 2012, 12:56:44 PM5/7/12
to rubyonra...@googlegroups.com
Jeremy Walker wrote in post #1059759:
> On 6 May 2012 22:13, Guillem Vidal <li...@ruby-forum.com> wrote:
>
>> > 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.

Guillem Vidal

unread,
May 7, 2012, 2:25:57 PM5/7/12
to rubyonra...@googlegroups.com
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)

Rodrigo Vieira

unread,
May 7, 2012, 8:49:06 PM5/7/12
to rubyonra...@googlegroups.com
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.

Sent from my iPod

On 06/05/2012, at 16:22, Guillem Vidal <li...@ruby-forum.com> wrote:

Reply all
Reply to author
Forward
0 new messages