This might be silly, but I'm including a gem which represents all the models I need for my project. I want to add a method, to_custom_string
to one of those models, Person
.
I was attempting to do this via (following this example):
config/initializers/extensions/person.rb
Which contained something like:
class Person < ActiveRecord::Base
def to_custom_string
address.street.to_s
end
end
The Person
class in the gem has a has_one :address
association.
The problem I was experiencing was that this patch seems to override the Person
class from the gem, instead of patching it. What's crazy is that this override behavior was only experienced via rake (all of the associations declared in the Person
class from the gem are lost).
My rake task was something like:
namespace :convert
task :all_persons => :environment do
Person.where(:param => value).includes(:address).find_in_batches(:batch_size => 2000) do |persons|
persons.each do |person|
puts person.to_custom_string
end
end
end
end
calling bundle exec rake convert:all_persons
gave me:
Association named 'address' was not found; perhaps you misspelled it?
But copying and pasting the code in the rake task into rails console worked fine.
My current solution is to copy the code for Person
from the gem into my app/models
directory, and have my to_custom_string
method there, which I know is wrong.
Can someone please explain why a) irb preserved my Person
associations, but rake did not, and b) how I can get rake to cooperate?
Thank you!
First of all instead of reopening the class I would create a Module and include it into the Person. So it would look like that
module CustomString
def to_custom_string
address.street.to_s
end
end
Person.send(:include, CustomString)
Also it seems like the Person model is not yet available at the point of running the initializer. You may want to put this in your application.rb if still doesn't work.
config.railties_order = [ModelEngine::Engine, :main_app, :all]
I guess the reason why it works in irb and not in rake is because they look up classes differently. Irb (which I believe you run by running rails console) loads all the classes at once therefore it loads the classes from engine, then it runs the initializer where you have the classes from engine already defined. I guess (though I'm not sure) Rake in development mode uses lazy loading of constants. So it doesn't load all the classes at the very beginning and only when it finds a constants that is undefined. Then it starts looking for a file that may define that constant. Since you put some Person in initializer it doesn't look up the engine's model at all cause at the point it sees Person it has the Person definition already. That's why the inclusion of module instead of reopening the class may help -> it enforces that it will lookup the Person constant from engine.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With