RoR - Where to put/initialize constant for a lib module - ruby-on-rails

In my Rails 3 application, I have a module in the lib/ folder. The module requires a constant variable, which is a big dictionary loaded from a data file. Since the dictionary won't change over the course of the application and its time consuming to reload this data file everytime a method from the module is called, I want to create a constant which holds the dictionary that can be accessed by the module in the lib.
lib/my_module:
module My_Module
def do_something(x)
y = CONSTANTVAR[x]
...
end
end
to initialize the constant, I have to load a file:
file = File.new('dataFile.dat','r') #I'm not sure where to put this data file
file.each_line { |line|
lineInfo = line.split
CONSTANTVAR[line[0]] = line[1] }
file.close
Where is the standard place to initialize variables that can be accessed by modules in the lib folder (this is the only place I will be accessing the variable)?
Also, the module loads a data file, is it standard to put data files in the lib/ folder as well?
Thanks!

You can take a look on how it is done here: https://github.com/sevenwire/forgery
It is a lib for generating words and it uses dictionaries. They are saved in : /lib/forgery/dictionary/*
So, save you dictionary on /lib/module-name/dictionaries/DATA.dat
And you can initialise your variable in config/initialisers/module-name.rb

I should put my, say, init_dictionary.rb in config/initializers. I think it's the better place for your requirement.

Related

Rails: Where to define constants with Classes?

I have a constant that is based on classes I define in lib:
ALL_DEMOGRAPHICS = [Demographic::Gender,
Demographic::Age]
I tried putting them in config/initializers, but they would get cached and not update even when I saved a new version of the class/file.
Where should I put this constant?
I tried putting them in config/initializers, but they would get cached and not update even when I saved a new version of the class/file.
You could define them in a module. Create a file called global_constants.rb in your models directory and add constants there:
app/models/global_constants.rb
module GlobalConstants
ALL_DEMOGRAPHICS = [Demographic::Gender, Demographic::Age]
end
Then you can use the constants like so:
GlobalConstants::ALL_DEMOGRAPHICS
If you keep the module in lib folder, then make sure you have added lib to autoload:
config/application.rb
config.autoload_paths << Rails.root.join('lib')

Changing YAML file without restarting Rails 4

I want to be able to edit a YAML file and reload it in a Rails 4 app. Right now I am loading the YAML file via an initializer, and I know that this will load the file only once and a restart will be required after changing it.
How could I accomplish a YAML reloading/refreshing as it is accomplished via i18n YAML files in Rails?
You can try something in the lines of checking for file's change time, for example:
module MyFileReader
def self.my_yaml_contents
if #my_yaml_file_ctime != File.ctime(file_name)
#my_yaml_contents = YAML.load(File.open(file_name))
#my_yaml_file_ctime = File.ctime(file_name)
end
#my_yaml_contents
end
end
MyFileReader.my_yaml_contents method will load and parse the file only on startup and change and serve the already parsed data in the meantime,
see http://www.ruby-doc.org/core-2.0.0/File.html#method-c-ctime
When you load the file, I assume you assign it to some variable or constant. If instead you don't assign it, then the load will be performed every time.
Instead of:
CONTENT = Yaml.load_file('your_file.yml')
create a simple class or function:
module YourFileReader
def self.load
Yaml.load_file('your_file.yml')
end
end
and use the defined method to read the file in your app
YourFileReader.load
or even simpler, use
Yaml.load_file('your_file.yml')
directly in your app where you need to read the file.
Instead of require use load to load the file.
require will load files only once. But load will load when it is called.
See more about this here http://ionrails.com/2009/09/19/ruby_require-vs-load-vs-include-vs-extend/

Ruby Rails Lib Folder Naming Convention

I seem to be having trouble with the naming conventions of the Lib Folder in Rails, and the error messages provided to me do not help. [For example, I have received a message saying that XXX::YYY::TextBox is expected to be defined xxx/yyy/text_box.rb, even though it clearly was defined there.] I think I'm getting the convention wrong.
Let's say I am working on YourModule::MyModule::MyClass. I clearly get that this file should be located in
lib/your_module/my_module/my_class.rb
But what should the actual file here look like? Which one of these (if either) are correct?
#your_module/my_module/my_class.rb
module YourModule
module MyModule
class MyClass
...
end
end
end
Or
#your_module/my_module/my_class.rb
class MyClass
...
end
In other words, do I need to nest the class inside of the module structure or not?
The lib folder has few conventions, as it is not autoloaded. So, how you organize the files is up to you, but you do have to name the classes correctly. Your first example is correct.
To get the files included you need to specify you want them in your application.rb file, see this example: Best way to load module/class from lib folder in Rails 3?
I would recommend making a folder just called lib/modules, since you probably won't have very many. Name the file my_class.rb. Then in application.rb you need:
config.autoload_paths += %W(#{config.root}/lib/modules)
That should take care of your issue.

Module gets reloaded every request so initialized data are lost

I store a value in a class variable inside of a module, such as:
module TranslationEnhancer
def self.install! klass
#dictionaries ||= [] << klass
end
...
end
I call this from an initializer in config/initializers:
require Rails.root + "lib" + "translation_enhancer.rb"
TranslationEnhancer::install! TranslationDictionary
Now, if I start the server in development environment, everything is ok during the first request. However, after that request, #dictionaries are suddenly nil. I have commented all other code in TranslationEnhancer, so I am absolutely sure the whole module must get reloaded every time I do a request.
I tried to move the module outside of the lib directory (moved it to lib_unloadable), then I tried:
ActiveSupport::Dependencies.explicitly_unloadable_constants << "TranslationEnhancer"
but failed again. I have no idea how to solve this, please help.
Got Ruby 1.9.2 # Rails 3.1.rc4.
EDIT: I know I could set the dictionaries as a constant. But I would like to use TranslationEnhancer as a library - so I could use it unchanged in a different project and install different Directories, such as:
TranslationEnhancer.install! EnglishDirectory, FrenchDirectory
These values won'd change during the runtime, they will just change project to project.
Solved!
I realized that the whole application.rb and environment.rb files are reloaded along with all other files. The only thing that does not get reloaded are initializers (config/initializers/*). The solution was to move the initialization to application.rb.
#dictionaries is not a "class variable". It is a "class-level instance variable".
Look here for a better explanation: Class and instance variables
Try using ##dictionaries instead.

Subfolders in lib

I have a module called user_searches. It performs some searches that aren't core to the user model, thus, why I'm putting the responsibility somewhere else. I want to organize all my models like this that perform non-core user functions in a lib subfolder called user. Right now to include the module's methods in the User model I have to put...
require 'user/user_searches'
class User < ActiveRecord::Base
include UserSearches
end
...I don't need the require if the file is directly in the lib folder, but do if it's in the subfolder. What do I have to do so I don't need the require?
You could put the necessary require lines into lib/user.rb that way, all requirements are loaded recursively on application launch.
Alternatively, you could put something like this into an initializer:
# put into config/initializers/load_lib.rb
Dir["#{RAILS_ROOT}/lib/**/*.rb"].each { |f| require(f) }
It will require all ruby files in your lib folder. You just have to make sure if this is really what you want :)
This is works that cause
in file rails-2.2.2/lib/initializer.rb in method default_load_paths initialized to load path just the lib folder without subdirectories, to solve this you can edit your project ` environment.rb config file and push into config.load_path array all subdirs.

Resources