I have an API wrapper with the following code:
module MyApi
mattr_accessor :app_id
end
I'm trying to set the value of app_id in an initializer like this:
# config/initializers/my_api.rb
MyApi.app_id = Rails.application.secrets.my_api["app_id"]
In my secrets file I have:
# secrets.yml
development:
my_api:
app_id: foo
But when I open my console or run tests I get this:
master ✗ $ rails c
Loading development environment (Rails 4.1.4)
2.2.0 :001 > MyApi.app_id
=> nil
2.2.0 :002 > MyApi.app_id = Rails.application.secrets.my_api["app_id"]
=> "foo"
2.2.0 :003 > MyApi.app_id
=> "foo"
I've followed gem readme's about using initializers but have never implemented one myself. Is there something I'm missing here? Using Rails 4.1.4.
Try adding this inside your module:
module MyApi
### Your code here
private
def self.setup
yield self
end
end
And in the initializer change it to have a setup block:
MyApi.setup do |config|
config.app_id = Rails.application.secrets.my_api["app_id"]
end
I have only built a few gems with initializers, but this worked for me.
Related
This question already has an answer here:
Rails table_name_prefix is not working as expected
(1 answer)
Closed 1 year ago.
I have this code:
# app/models/ta.rb
module Ta
def self.table_name_prefix
'ta_'
end
end
...
# app/models/ta/article.rb
module Ta
class Article < ActiveRecord::Base
end
end
From the rails console...
# development environment
Loading development environment (Rails 4.1.6)
2.1.3 :001 > Ta::Article.table_name
=> "ta_articles"
2.1.3 :002 >
...
# production environment
Loading production environment (Rails 4.1.6)
2.1.3 :001 > Ta::Article.table_name
=> "articles"
2.1.3 :002 >
Why is this happening?
Add to config/initializers/namespace.rb something like:
require Rails.root.join('app', 'models', 'ta')
should solve your problem.
I have a Ruby on Rails app with an API in lib. Files in lib are autoloaded, and the API is configured in an initializer.
# lib/my_api.rb
module MyApi
extend Configuration
end
# lib/my_api/configuration.rb
module MyApi
module Configuration
attr_accessor :my_setting
def configure
yield self
end
end
end
# config/initializers/my_api.rb
MyApi.configure do |config|
config.my_setting = 'foo'
end
This works in production, but in development the API gets configured when the server is started. After I change some code, the configuration is lost and there are errors because the settings are nil:
irb(main):001:0> MyApi.my_setting
=> "foo"
irb(main):002:0> reload!
Reloading...
=> true
irb(main):003:0> MyApi.my_setting
=> nil
My guess is that in development, the classes are reloaded, but the initializer is not, which means it only gets configured once after starting the server.
Right now I'm duplicating my configuration in lib/my_api.rb, but that's very hacky.
What's a clean solution for this problem?
module MyApi
module Configuration
mattr_accessor :my_setting
def configure
yield self
end
end
end
mattr_accessor is an ActiveSupport macro for creating module level accessors.
Well, until someone comes up with a better solution, I've come up with two workarounds. I went with 2.
Don't autoload the lib directory (meaning don't autoload the API). That means having to restart the server when the API code changes, but solves the problem. That's why configuring gems like this works -- because they aren't autoloaded.
Manually reload the initializer in development at the end of lib/my_api.rb:
load Rails.root.join('config/initializers/smart_meter.rb') if Rails.env.development?
The MyApi constant will be replaced by a new one when Rails autoloads classes. The configuration is still available on the old object:
Loading development environment (Rails 4.2.0)
irb: warn: can't alias context from irb_context.
irb(main):001:0> MyApi.my_setting
=> "foo"
irb(main):002:0> OldMyApi = MyApi
=> MyApi
irb(main):003:0> reload!
Reloading...
=> true
irb(main):004:0> MyApi.my_setting
=> nil
irb(main):005:0> OldMyApi.my_setting
=> "foo"
irb(main):006:0> load Rails.root.join('config/initializers/smart_meter.rb')
=> true
irb(main):007:0> MyApi.my_setting
=> "foo"
When I try to use the webdriver-user-agent gem, I cannot access the module, let alone its methods.
in Rails.root/Gemfile.lock:
GEM
remote: https://rubygems.org/
specs:
# ...
watir-webdriver (0.6.10)
selenium-webdriver (>= 2.18.0)
webdriver-user-agent (7.1)
facets
json
selenium-webdriver
# ...
in Rails.root/app/models/some_model.rb:
class SomeModel < ActiveRecord::Base
def some_function
driver = WebDriver::UserAgent.driver(browser: :firefox, agent: :iphone, orientation: :portrait)
# other functionality ...
end
end
Load environment
rails c
Using the class:
2.0.0-p353 :001 > s = SomeModel.last
2.0.0-p353 :002 > s.some_function
NameError: uninitialized constant SomeModel::WebDriver
Is Rails looking for the Module in the wrong place by looking for it within SomeModel? Am I accessing this incorrectly? The module not is available:
2.0.0-p353 :003 > Webdriver::UserAgent
NameError: uninitialized constant WebDriver # corrected on edit
I've tried including require 'webdriver-user-agent' at the top of the class file, and then include WebDriver -- same error, but on loading of the model instance.
I filed a bug report in the repo, but I'm sure I'm doing something dumb here...
Additional info:
Centos 6.5
Rails 4.1.4
Ruby 2.0
Rubygems 2.2.2
You are trying to look for the module:
WebDriver
However, the webdriver-user-agent gem uses the module:
Webdriver
Notice the difference in the lowercase 'd'. Class and module names are case-sensitive, which is why the constant is not being found.
The function should work by correcting the module name:
class SomeModel < ActiveRecord::Base
def some_function
driver = Webdriver::UserAgent.driver(browser: :firefox, agent: :iphone, orientation: :portrait)
# other functionality ...
end
end
Can any one tell me the best practice for initializing config variables and read that variables in gems?
Have tried with the following steps:
This code is written in gem
config = YAML.load_file("#{RAILS_ROOT}/config/config.yml")
#key = config["config"]["key"]
server = config["config"]["server"]
and created yml file in config/config.yml in rails application.
Thanks in advance,
Jagdish
I did it once like following:
module YourGem
class YourClass
#config = { :username => "foo", :password => "bar" } # or #config = SomeHelperClass.default_config if the config is more complex
#valid_config_keys = #config.keys
# Configure through hash
def self.configure(opts = {})
opts.each { |k,v| #config[k.to_sym] = v if #valid_config_keys.include? k.to_sym }
end
# Configure through yaml file
def self.configure_with(path_to_yaml_file)
begin
config = YAML::load(IO.read(path_to_yaml_file))
rescue => e
raise "YAML configuration file couldn't be found: #{e}"
end
configure(config)
end
end
end
And in your Rails Application, where you require your gem, you can add an initializer and configure like following:
config/initializers/your_initializer.rb
YourGem::YourClass.configure_with(path_to_the_yml_config_file)
This solution provides a default config, and the possibility to add a own yaml file to change the default values.
I've found my favourite way to set config variables in rails is using the figaro gem. Figaro basically makes use of the ENV['x'] method that is available throughout rails. It stores all your config variables inside a common application.yml file and makes all the constants accessible via the ENV variable.
The bonus is that this translates 1 to 1 with the way Heroku does things as well.
I would think this is a Ruby difference, but I'm using the same Ruby version 1.8.7. This is related to this post (to answer "why do you need this?"). This code works in 2.2.2
Loading development environment (Rails 2.2.2)
>> module ActionMailer
>> Utils.normalize_new_lines("blah")
>> end
but in 2.3.5 it fails
Loading development environment (Rails 2.3.5)
>> module ActionMailer
>> Utils.normalize_new_lines("blah")
>> end
NoMethodError: undefined method `normalize_new_lines' for ActionMailer::Utils:Module
from (irb):2
What's new about 2.3.5 that this would fail? The method is there in 2.3.5, so this works
Loading development environment (Rails 2.3.5)
>> include ActionMailer
>> include Utils
>> normalize_new_lines("blah")
I realize this is probably an important Rails difference.
Looks like the code changed from version 2.2 to version 2.3.5
old:
module ActionMailer
module Utils #:nodoc:
def normalize_new_lines(text)
text.to_s.gsub(/\r\n?/, "\n")
end
module_function :normalize_new_lines
end
end
new:
module ActionMailer
module Utils #:nodoc:
def normalize_new_lines(text)
text.to_s.gsub(/\r\n?/, "\n")
end
end
end
I guess you could restore the old behavior by calling module_function yourself:
$ script/console
Loading development environment (Rails 2.3.5)
>> module ActionMailer
>> module Utils
>> module_function :normalize_new_lines
>> end
>> Utils.normalize_new_lines("blah")
>> end
=> "blah"
>>
EDIT: Or better yet just include the module (per Simone)
>> include ActionMailer::Utils