I'm working on a Rails 3 application (specifically 3.2.13) on ruby 1.9.3-p392.
In one of my controllers The "create" action can receive an image (as a ActionDispatch::Http::UploadedFile)
I'm trying to monkeypatch ActionDispatch::Http::UploadedFile by overriding its as_json method to return the tempfile path instead of the tempfile File object itself.
The reason why I'm doing this is because I have a database logger that serializes the log context (which includes the request params) by calling to_json on the context.
Problem is that calling to_json on said class produces a ton of binary data which fill up my log.
So I have created the following directory structure under "lib":
"action_dispatch/http/uploaded_file.rb"
Inside this file the class is named ActionDispatch::Http::UploadedFile
I've also added the lib folder to application.rb by:
config.autoload_paths += Dir["#{config.root}/lib"]
Problem is that rails doesn't load my monkey-patched class.
If I add require "action_dispatch/http/uploaded_file"to the top of my controller file everything works fine.
Why doesn't Rails autoloads my monkey-patched class?
The directory structure and class naming is according to the Rails conventions.
Move your code to config/initializers/your_filename.rb file. The code in these files is loaded during Rails Application boot process.
That's in general. But I'm not sure why you want to monkey-patch ActionDispatch::Http::UploadedFile class, because I haven't got much info about your app.
try
config.autoload_paths += ["#{config.root}/lib"]
Related
I want to build an index for different objects in my Rails project and would like to add a 'count_occurences' method that I can call on String objects.
I saw I could do something like
class String
def self.count_occurences
do_something_here
end
end
What's the exact way to define this method, and where to put the code in my Rails project?
Thanks
You can define a new class in your application at lib/ext/string.rb and put this content in it:
class String
def to_magic
"magic"
end
end
To load this class, you will need to require it in your config/application.rb file or in an initializer. If you had many of these extensions, an initializer is better! The way to load it is simple:
require 'ext/string'
The to_magic method will then be available on instances of the String class inside your application / console, i.e.:
>> "not magic".to_magic
=> "magic"
No plugins necessary.
I know this is an old thread, but it doesn't seem as if the accepted solution works in Rails 4+ (at least not for me). Putting the extension rb file in to config/initializers worked.
Alternatively, you can add /lib to the Rails autoloader (in config/application.rb, in the Application class:
config.autoload_paths += %W(#{config.root}/lib)
require 'ext/string'
See this:
http://brettu.com/rails-ruby-tips-203-load-lib-files-in-rails-4/
When you want to extend some core class then you usually want to create a plugin (it is handy when need this code in another application). Here you can find a guide how to create a plugin http://guides.rubyonrails.org/plugins.html and point #3 show you how to extend String class: http://guides.rubyonrails.org/plugins.html#extending-core-classes
I'm trying to extend the String class in my Rails 4.2 app. I created a lib/string.rb file to hold the extensions.
class String
def testing
"testing"
end
end
I added lib to autoload_paths in application.rb.
config.autoload_paths << Rails.root.join('lib')
When I startup the rails console and execute "".testing, I get NoMethodError: undefined method 'testing' for "":String
Can anyone explain why this method isn't getting picked up? I have a hunch that it's because the String constant is already loaded, so Rails doesn't need to autoload the constant. As a result, it never tries to load the lib/string.rb file and my method never gets added to String.
When I explicitly require the file in an initializer, I can get the method loaded, but if I change the method, I have to restart the server to get rails to see the change. It feels like I'm missing something. It seems like there should be a way to get Rails to automatically read core extension classes and reload them when the file changes.
Yep, you're right. It will not autoload string since it's already defined. I usually put core class extensions inside an initializer. So config/initializers/string.rb
I'm trying to add a method to the DateTime class like so:
class DateTime
def ymd(sep = "/")
strftime("%Y#{sep}%m#{sep}%d")
end
end
I put this in #{config.root}/lib/datetime.rb and updated the autoload_path to include #{config.root}/lib (since that seems to go in and out of the conventional autoload path). That didn't work, so I also tried putting it in a random directory (#{config.root}/blah and added that path to the autoload_paths line in the config).
In all of the above cases, I'm only able to use the new method in the rails console if I require 'datetime' first, and I'm not able to use it in controllers or view templates no matter what I do.
So,
Should the file be called datetime.rb or date_time.rb? (I've tried both so far and neither are currently working)
Where should I be putting this file so I can use the new method in models, controllers and views?
Any idea why I can require it in the console, but it doesn't autoload there?
The app is currently running rails 3.2.21, but I'll switch to rails 4 at some point so answers for either version are appreciated.
I'm having a problem with a module name and the folder structure.
I have a model defined as
module API
module RESTv2
class User
end
end
end
The folder structure looks like
models/api/restv2/user.rb
When trying to access the class, I get an uninitialized constant error. However, if I change the module name to REST and the folder to /rest, I don't get the error.
I assume the problem has to do with the naming of the folder, and I've tried all different combos of /rest_v_2, /rest_v2, /restv_2, etc.
Any suggestions?
Rails uses the 'underscore' method on a module or class name to try and figure out what file to load when it comes across a constant it doesn't know yet. When you run your module through this method, it doesn't seem to give the most intuitive result:
"RESTv2".underscore
# => "res_tv2"
I'm not sure why underscore makes this choice, but I bet renaming your module dir to the above would fix your issue (though I think I'd prefer just renaming it to "RestV2 or RESTV2 so the directory name is sane).
You'll need to configure Rails to autoload in the subdirectories of the app/model directory. Put this in your config/application.rb:
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
Then you should be able to autoload those files.
Also, your likely filename will have to be app/model/api/res_tv2/user.rb, as Rails uses String.underscore to determine the filename. I'd just call it API::V2::User to avoid headaches, unless you have more than one type of API.
Using Rails 3.2 and ruby 1.9.3p0
I am trying out the gem delayed_job. I have created a file lib/mailing_job.rb in which I have class MailingJob.
In a controller under app/controllers/requests_controller.rb I am calling
job = MailingJob.new(#request)
but this is returning the error
uninitialized constant RequestsController::MailingJob
I think it is because I need a proper way of referencing a class under a different folder structure.
Any idea how I can isntantiate class MailingJob from a different file (class) in a different folder?
Rails 3 does not include the lib folder within the load path so your application does not know how to find the class.
You can modify config/application.rb and add a line to instruct rails to also look in the lib folder like so
config.autoload_paths += %W(#{config.root}/lib)
In an initializer (e.g. config/initializers/delayed_job.rb), do this (doesnt matter where)
require 'mailing_job'