Unload a ruby class
Object.send(:remove_const, :Foo)
assuming your class is named Foo
.
Is it possible to 'unload' ('un-require') a Ruby library?
Like @Alex said, you could use the Kernel#fork
to create a new ruby process where you will require
your libraries. The new forked process will have access to data loaded in the parent process:
def talk(msg)
# this will allow us to see which process is
# talking
puts "#{Process.pid}: #{msg}"
end
# this data was loaded on the parent process
# and will be use in the child (and in the parent)
this_is_data = ["a", "b", "c"]
talk "I'm the father process, and I see #{this_is_data}"
# this will create a new ruby process
fork{
talk "I'm another process, and I also see #{this_is_data}"
talk "But when I change `this_is_data`, a new copy of it is created"
this_is_data << "d"
talk "My own #{this_is_data}"
}
# let's wait and give a chance to the child process
# finishes before the parent
sleep 3
talk "Now, in the father again, data is: #{this_is_data}"
The result of this execution will vary in your machine, the Process.id
will return different values, but it will be like these:
23520: I'm the father process, and I see ["a", "b", "c"]
23551: I'm another process, and I also see ["a", "b", "c"]
23551: But when I change `this_is_data`, a new copy of it is created
23551: My own ["a", "b", "c", "d"]
23520: Now, in the father again, data is: ["a", "b", "c"]
And this is good! Each process created by fork
is an O.S. level process and run in it's own memory space.
Another thing you can do to somehow manage the globals created by loading a file, is replace the use of require
by load
. This approach doesn't solve all the problems already pointed, but really can help. See the following specs:
require "minitest/autorun"
describe "Loading files inside a scope" do
def create_lib_file(version)
libfile = <<CODE
class MyLibrary#{version}
VERSION = "0.0.#{version}"
end
class String
def omg_danger!
end
end
puts "loaded \#{MyLibrary#{version}::VERSION}"
CODE
File.write("my_library.rb", libfile)
end
after do
File.delete("my_library.rb") if File.exists?("my_library.rb")
end
describe "loading with require" do
it "sees the MyLibrary definition" do
create_lib_file("1")
require_relative "my_library.rb"
MyLibrary1::VERSION.must_be :==, "0.0.1"
"".respond_to?(:omg_danger!).must_be :==, true
end
end
describe "loading with #load " do
describe "without wrapping" do
it "sees the MyLibrary definition" do
create_lib_file("2")
load "my_library.rb"
MyLibrary2::VERSION.must_be :==, "0.0.2"
"".respond_to?(:omg_danger!).must_be :==, true
end
end
describe "using anonymous module wraping" do
it "doesn't sees MyLibrary definition" do
create_lib_file("3")
load "my_library.rb", true
->{ MyLibrary3 }.must_raise NameError
"".respond_to?(:omg_danger!).must_be :==, false
end
end
end
end
And the result of execution:
Run options: --seed 16453
# Running tests:
loaded 0.0.3
.loaded 0.0.2
.loaded 0.0.1
.
Finished tests in 0.004707s, 637.3486 tests/s, 1274.6973 assertions/s.
3 tests, 6 assertions, 0 failures, 0 errors, 0 skips
how do I unload & load a class?
Not sure it that is the problem, but in your application.rb
you need to add the following line:
config.autoload_paths += %W( #{config.root}/lib )
And secondly, to make sure that classes/modules are found correctly on reload, the naming has to follow Rails conventions. This means that snake-casing a module or class name should give the filename, and different namespaces (or nesting) should be in different folders.
Some examples to make this more clear :)
class SomeClass --> /lib/some_class.rb
class SomeHTTPStuff --> /lib/some_http_stuff.rb
class API::Stuff --> /lib/api/stuff.rb
HTH.
Force Class Loading and Unloading (RoR)
Since you tagged the question with Rails, then you can do
some_class_name.constantize
Example
"User".constantize
# => User
remove_const
works, but you need to call it from the object space where the constant is defined. Also, remember to pass a symbol as the constant name.
Example
Object.send(:remove_const, :Foo)
Can I Unload a Rails Metal Class after one time use?
A simplest solution (although not quite as clean) would be to store the fact that an admin user exists in the class.
class EnsureAdminUser
def self.call(env)
if @admin_defined or Admin.any?
@admin_defined = true
[404, {"Content-Type" => "text/html"}, "Not Found"]
else
…
end
end
end
This saves you the DB hit on each request.
To actually delete the metal you will need to do something a bit more radical (and evil):
ObjectSpace.each_object(Rails::Rack::Metal){|metal_handler|
metal_handler.instance_eval{ @metals.delete(EnsureAdminUser) }
}
how to unload the files loaded by the require statement in rails
I have resolved that problem using the config.cache_classes = true
in the environment.
Is it possible to unload an ActiveRecord association?
Part 1: Solution to the stated problem:
To empty the loaded association data, use the target
method on the association:
location.state.cities.target=[]
If you access the cities
now:
location.state.cities
=> []
Part 2: Clumsy way to avoid the problem:
Avoid loading the association while accessing cities
. Use
self.state.cities.all
Instead of
self.state.cities
Part 3: Something smells fishy:
Why are you storing objects in to flash? Flash is generally meant for sending text messages. If you assign non strings to flash you will run in to the cookie size limit in no time.
Also when you are validating why do you need to load all the cities? Does this mean you are validating in Ruby? Can you post the validation code. In most cases you can optimize this by moving validation to DB.
Edit: Extended the answer based on the comment
I follow this pattern in Rails 2.3.x. The variables I want to access in the view associated with edit
action is always a subset of variables available in update
action.
class ProductsController < ApplicationController
before_filter :init_data, :only => [:new, :create, :edit, :update,
:destroy, :show]
def update
@product.attributes = params[:product]
if @product.save
flash[:notice] = "Successfully saved the product."
redirect_to product_path(@product)
else
render :action => 'edit'
end
end
private
def init_data
switch(action.to_sym)
when :new, :create
@product = Product.new(params[:product])
when :edit, update, :destroy, :show
@product = Product.find(params[:id])
end
end
end
Related Topics
Do All? and Any? Guarantee Short-Circuit Evaluation
Switch to Popup Windows in Cucumber, Capybara
In Ruby/Rails, How to Sort on a Date Value Where the Date Can Sometimes Be Null
Controller Can Not Detect Ajax Requests
How to Get Out of a "Hung" State in Irb
Is There a Ruby Method That Just Returns the Value of a Block
Is There a Best Directory to Place Image Uploads on Heroku
How to Preserve Case with Http.Get
Camelcase Column in Postgresql Database in Rails (Activerecord)
Rails 4 Session.Id Occasionally Nil
Splitting String into Pair of Characters in Ruby
Can't Reindex Sunspot Solr - Error - Rsolr::Error::Http - 500 Internal Server Error