I have this code which is in lib folder. This code works outside of rails, but when it's called from the rails controller I get the uninitialized constant AWS::S3::Base error
require 'rubygems'
require 'aws/s3'
module S3Util
def self.upload_file(local_file)
mime_type = "application/octet-stream"
bucket = "test"
AWS::S3::Base.establish_connection!(
:access_key_id => '*****',
:secret_access_key => '****'
)
base_name = File.basename(local_file)
puts "**** Uploading #{local_file} as '#{base_name}' to '#{bucket}'"
AWS::S3::S3Object.store(
base_name,
File.open(local_file),
bucket,
:content_type => mime_type
)
puts "***** Uploaded!"
end
end
just do in your controller
require 'aws/s3'
and its work for me
Rails doesn't "know" that the module is available to the application; you have to add it to the paths it looks in. You can do that in a couple of ways, but most people do the following.
Add this line to your config/application.rb:
config.autoload_paths += Dir["#{config.root}/lib/**/"]
You may, at some point, want to be more specific about which directories are searched, but this should get you going.
Related
I have a namespace issue. MyModel is just a normal Rails Model. However, my code seems to be namespacing it under the namespace I created, I need a way to reference it directly without the AppName::Loader::ModelImport namespace.
Error:
NameError: uninitialized constant AppName::Loader::ModelImport::MyModel
Rake task:
require 'csv'
require_relative '../appname/loader/model_import'
namespace :app_name do
namespace :loader do
desc "Loads data into Database"
task model_import: :environment do
include AppName::Loader::ModelImport
end
end
end
Service Object
./appname/loader/model_import.rb
module AppName
module Loader
module ModelImport
record_set = []
file_name = File.join(Rails.root, 'lib','appname','loader','data' ,'data.txt')
CSV.open(file_name, "r", { :col_sep => "\t", quote_char: nil, row_sep: "\r\r\n" }).each do |row|
record_set << MyModel.new(
company_name: row[1],
address1: row[2],
address2: row[3],
city: row[4],
state_code: row[5],
zip_code: row[6]
)
end
MyModel.import record_set
end
end
end
I tried:
::MyModel.new()
and also got the >>NameError: uninitialized constant MyModel, so I wonder if rails is not loading properly. However, I thought task model_import: :environment do loads Rails.
My application.rb file has..
config.eager_load_paths << Rails.root.join("lib")
If I use Pry, I can see the 'Rails' constant is loaded. However, I can not access any of my models. For example, User does not load, nor any other.
Solution per comments by Tom Lord:
require needed to be evaluated after the environment has been loaded.
If you write a module the code inside it may automagically get executed just because you required the module. For example:
module AppName
module Loader
module ModelImport
puts 'wtf' # this may get run but you won't see it
end
end
end
However if you have at least method defined it can be called
module AppName
module Loader
module ModelImport
def self.wtf
puts 'wtf'
end
end
end
end
Now if this file is saved in lib/app_name/loder/model_import.rb you can run it like this:
require_or_load 'lib/app_name/loader/model_import'
# and now you can do
AppName::Loader::ModelImport.wtf
=>wtf
So you need to first define a usable module, then you can require it, then you can call methods on it.
Following the tutorial, I created a file omniauth.rb at the path
spec/support/helpers/omniauth.rb
module Omniauth
module Mock
def auth_mock
OmniAuth.config.mock_auth[:twitter] = {
'provider' => 'twitter',
'uid' => '123545',
'user_info' => {
'name' => 'mockuser'
},
'credentials' => {
'token' => 'mock_token',
'secret' => 'mock_secret'
}
}
end
end
end
But when I run rspec, I get an error with "uninitialized constant Omniauth"
rails-omniauth/spec/support/helpers.rb:2:in `block in <top (required)>': uninitialized constant Omniauth (NameError)
It seems clear that either omniauth.rb or helpers.rb should be in a different location, but I don't know where.
Update:
I subsequently tried installing the rails-omniauth via the Rails Composer app. When I run "rspec" for this app, I get exactly the same error.
At one point in the tutorial you are given a choice between creating a file at at /spec/support/helpers.rb:
RSpec.configure do |config|
config.include Omniauth::Mock
config.include Omniauth::SessionHelpers, type: :feature
end
OmniAuth.config.test_mode = true
Or adding these same lines to /spec/rails_helper.rb.
I created the new file at /spec/support/helpers.rb. To make this work, I needed to add the line require_relative 'helpers/omniauth' at the top of the file. The Rails Composer app also adds the helpers.rb file rather than editing rails_helper.rb, so the same line is needed to make rspec run successfully for that app.
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"
I have a custom class stored in /lib (/lib/buffer_app.rb):
require 'HTTParty'
class BufferApp
include HTTParty
base_uri 'https://api.bufferapp.com/1'
def initialize(token, id)
#token = token
#id = id
end
def create(text)
message_hash = {"text" => text, "profile_ids[]" => #id, "access_token" => #token}
response = BufferApp.post('/updates/create.json', :body => {"text" => text, "profile_ids[]" => #id, "access_token" => #token})
end
end
I'm attempting to use this this class in an Active Admin resource and get the following error when in production (Heroku):
NameError (uninitialized constant Admin::EventsController::BufferApp):
It's worth noting I have this line in my application.rb and that this functionality works locally in development:
config.autoload_paths += %W(#{Rails.root}/lib)
If I try include BufferApp or require 'BufferApp' that line itself causes an error. Am I having a namespace issue? Does this need to be a module? Or is it a simple configuration oversight?
I had exactly the same problem with Rails 5 alpha. To solve it, I had to manually require the file:
require 'buffer_app'
and not: (require 'BufferApp')
Even if Michal Szyndel's answer makes great sense to me, after manually requiring the file, prefixing :: to the constant was non influential in my case.
Anyway I am not satisfied with the manual requiring solution because I need to add code which is environment specific. Why don't I need to require the files manually in development?
Change this
config.autoload_paths += %W(#{Rails.root}/lib)
to this
config.eager_load_paths += %W(#{Rails.root}/lib)
eager_load_paths will get eagerly loaded in production and on-demand in development. Doing it this way, you don't need to require every file explicitly.
See more info on this answer.
Error line says it all, you should reference class as ::BufferApp
I've placed the file rack_app.rb with simple Rack application in the lib directory:
class RackApp
def call env
[200, {}, 'Hello']
end
end
Then I've added this route:
match 'rack' => RackApp
And when I try to launch the rails server I get the following error:
config/routes.rb:65: uninitialized constant RackApp (NameError)
Rails 3 has no more autoloading by default. So you need require your file
require 'lib/rack_app.rb'
Or come back the autoloading in application.rb
config.autoload_paths += %W( #{config.root}/lib )
Include require 'email_format_validator' in the model.