I am getting this error when I am using
acts_as_ferret :fields =>[:competitor], :remote => true
NameError in PartController#index
uninitialized constant PartController::Competitor
My Model
class Competitor < ActiveRecord::Base
validates_presence_of :fee_earner_id, :notes
belongs_to :fee_earner
belongs_to :country
belongs_to :state
belongs_to :user
acts_as_ferret :fields =>[:competitor], :remote => true
end
My controller
class PartController < ApplicationController
def index
#proscribeds = Competitor.paginate(:all,
:order => sort ,
:page => params[:page],
:per_page => 70 )
end
end
Its working fine in localhost but when I deploy it in the server than I get this error.
act_as_ferret is working good with other models. I don't know why this is not working with only Competitor model.
These might seem like simplistic suggestions, but here's what comes to mind:
Do you have the same OS on localhost and the server? I've been burned by little discrepancies like the differences between how Unix and Windows handle mixed case pathnames.
Have the most updated versions of all your files been moved? Can you do a diff and ensure that there isn't a missing config file or environment variable or something?
I know those suggestions aren't really Rail/Ruby-specific, but I've found that little configuration problems tend to give me more headaches than actual code errors do.
Good luck!
This could be a problem with the bin/ferret_server file on the remote drb server you are running. What it is complaining about is that it knows nothing about the PartController::Competitor model. This is because the ferret-server does not eager load all the Rails classes like Rails does by default.
I had a similar issue and the solution was to also require the Rails config/environment file as well as the Rails config/application file.
Something like this:
begin
ENV['FERRET_USE_LOCAL_INDEX'] = 'true'
if env = $ferret_server_options['environment']
ENV['RAILS_ENV'] = env
end
# determine RAILS_ROOT unless already set
root = File.expand_path(determine_rails_root)
begin
require File.join(root, 'config', 'application')
# Also require environment to eager load Rails classes
require File.join(root, 'config', 'environment')
rescue
puts "Error booting your rails app at #{root}: #{$!}\n#{$!.backtrace.join("\n")}"
raise $!
end
puts "Rails.root: #{Rails.root}"
puts "Rails.env: #{Rails.env}"
require 'acts_as_ferret/server/server'
ActsAsFerret::Server::Server.new.send($ferret_server_action)
rescue Exception => e
$stderr.puts(e.message)
$stderr.puts(e.backtrace.join("\n")) if $ferret_server_options['debug']
exit(1)
end
Related
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
My webapp needs to encrypt its session data. What I setup is:
config/initializers/encryptor.rb:
require 'openssl'
require 'myapp/encryptor'
MyApp::Encryptor.config[ :random_key ] = OpenSSL::Random.random_bytes( 128 )
Session.delete_all
app/models/session.rb:
require 'attr_encrypted'
class Session < ActiveRecord::Base
attr_accessible :session_id, :data
attr_encryptor :data, :key => proc { MyApp::Encryptor.config[ :random_key ] }, :marshal => true
# Rest of model stuff
end
That all works great, and keeps the session data secured. Here's the problem: when I run my custom rake tasks it loads the initializer and clears all the sessions. Not good!
What can I put in my initializer to make sure it ONLY runs for the webapp initialization? Or, what can I put in my initializer to make it NOT run for rake tasks?
Update: OK, what I've done for the moment is add MYAPP_IN_RAKE = true unless defined? MYAPP_IN_RAKE to my .rake file. And then in my initializer I do:
unless defined?( MYAPP_IN_RAKE ) && MYAPP_IN_RAKE
# Web only initialization
end
Seems to work. But I'm open to other suggestions.
You might make a modification to your application in `config/application.rb' like this:
module MyApp
def self.rake?
!!#rake
end
def self.rake=(value)
#rake = !!value
end
Then in your Rakefile you'd add this:
MyApp.rake = true
It's nice to use methods rather than constants since sometimes you'd prefer to change or redefine them later. Plus, they don't pollute the root namespace.
Here's a sample config/initializers/rake_environment_test.rb script:
if (MyApp.rake?)
puts "In rake"
else
puts "Not in rake"
end
The programmable nature of the Rakefile affords you significant flexibility.
There is another work around:
unless ENV["RAILS_ENV"].nil? || ENV["RAILS_ENV"] == 'test'
When you launch with rake your ENV["RAILS_ENV"] will be nil. The test for 'test' is to avoid to run when using rspec.
I know that is reckon to use Rails.env but it return "development" when it is not initialised.
http://apidock.com/rails/Rails/env/class
# File railties/lib/rails.rb, line 55
def env
#_env ||= ActiveSupport::StringInquirer.new(ENV["RAILS_ENV"]
|| ENV["RACK_ENV"] || "development")
end
In my adhearsion dialplan, I have the following code that is causing an immediate disconnect from the call without any output to the log or console:
the_flow = CallFlow.where(:dnis => dnis).first
CallFlow is a model in my rails app (gui/app/models/call_flow.rb), which lives in the gui directory of my adhearsion app. In my .ahnrc file I have:
paths:
# All paths are relative to this file's directory
init: config/startup.rb
dialplan: dialplan.rb
events: events.rb
models: gui/app/models/*.rb
And this is call_flow.rb:
class CallFlow < ActiveRecord::Base
belongs_to :routable, :polymorphic => true
def dialplan
puts self.routable.description.squeeze("\n").strip
end
def target_route=(params)
self.routable = params[:kind].constantize.new(params.reject {|k,v| k == "kind"})
end
end
And finally, I have the following line in config/startup.rb:
config.enable_rails :path => 'gui', :env => :development
I know the model works because I can create records using the rails server. But I don't even know how to get any information about what's going on to make the dialplan disconnect the call when it gets to that first line above.
Some things to check:
Ensure you have set logging to :debug in config/startup.rb
Ensure you have enabled either Rails integration or database integration, not both.
If you are running a version of Adhearsion prior to 1.1.0, some exceptions that occur in dialplan.rb may be silently lost. Consider upgrading to 1.1.0 or later (1.2.0 is current stable) and create an exception handler. This can be a simple message logger or you can report exceptions to Airbrake. See the bottom of this post for a simple Adhearsion exception logger.
Try starting the Adhearsion console to see if your models are loaded at all. Start the Adhearsion console with ahn start console /path/to/ahn/app. You will then have a console similar to the Rails console and should have access to all your ActiveRecord models (assuming the Rails integration loaded correctly).
Example exception logger for Adhearsion 1.1.0 or later. Put this in your events.rb:
events.exception.each do |e|
ahn_log.error e.message
ahn_log.debug e.backtrace.join("\n")
end
General notes on Rails vs. Database integration for Adhearsion:
For Rails integration have a line something like config.enable_rails :path => '/path/to/rails/app', :env => :production
For database integration, use something like:
config.enable_database :adapter => 'mysql',
:username => 'root',
:password => '',
:host => 'localhost'
For database integration only (not Rails integration), you should make sure that your models are in a place where Adhearsion can find them. The default location is models/ but this can be changed by editing the .ahnrc file in the Adhearsion app's base directory.
try to run this code in rails console
first start the console
bundle exec rails console
and then try to run the code which is causing the issue
CallFlow.where(:dnis => "something").first # replace "something" with something valid
A colleague and I are working in different projects that share some models. So, we are sharing the models through a git submodule.
Additionally, we'd like to be able to also share migrations:
In this way, my colleague's migrations would be in the folder db/migrate/other_db of my project.
How can I configure rails migrations to also run the migrations in this extra folder?
In your config file (config/application.rb for all environments or config/environments/$(environment).rb only for particular environment) add this line:
config.paths['db/migrate'] += 'db/migrate/other_db'
And if you want to change default 'db/migrate' path (config.paths['db/migrate'] is an array with one string 'db/migrate' by default), do this:
config.paths['db/migrate'] = ['db/my_migrate']
Here are default config.paths, which we also can change:
"app" => ["app"],
"app/assets" => ["app/assets"],
"app/controllers" => ["app/controllers"],
"app/helpers" => ["app/helpers"],
"app/models" => ["app/models"],
"app/mailers" => ["app/mailers"],
"app/views" => ["app/views"],
"lib" => ["lib"],
"lib/assets" => ["lib/assets"],
"lib/tasks" => ["lib/tasks"],
"config" => ["config"],
"config/environments" => ["config/environments"],
"config/initializers" => ["config/initializers"],
"config/locales" => ["config/locales"],
"config/routes" => ["config/routes.rb"],
"db" => ["db"],
"db/migrate" => ["db/migrate"],
"db/seeds" => ["db/seeds.rb"],
"vendor" => ["vendor"],
"vendor/assets" => ["vendor/assets"],
"vendor/plugins" => ["vendor/plugins"],
"config/database" => ["config/database.yml"],
"config/environment" => ["config/environment.rb"],
"lib/templates" => ["lib/templates"],
"log" => ["log/development.log"],
"public" => ["public"],
"public/javascripts" => ["public/javascripts"],
"public/stylesheets" => ["public/stylesheets"],
"tmp" => ["tmp"],
Update for Rails 5/6;
Rails 5 recommends setting additional migration paths in your config/database.yml file. It's very easy, see this example;
development:
migrations_paths:
- "db/migrate/other_db"
- "db/migrate/something_else"
ActiveRecord::Migrator.migrations_path= will be deprecated in Rails 6.
based on the answer by Swanand, we can write a migration to load the migrations in an external dir:
class MigrateMetadata < ActiveRecord::Migration
MIGRATIONS_PATH='db/migrate/metadata'
def self.up
Dir["#{MIGRATIONS_PATH}/[0-9]*_*.rb"].
sort.map{|filename|require filename}.flatten.
each{|class_name| const_get(class_name).up}
end
def self.down
Dir["#{MIGRATIONS_PATH}/[0-9]*_*.rb"].sort.reverse.
map{|filename|require filename}.flatten.
each{|class_name| const_get(class_name).down}
end
end
By the way, if you are building a gem to work with Rails, you can place a block like the following in your rail tie to add the gem's own migrations.
root = ... # the path to your gem
initializer :append_migrations do |app|
unless app.root.to_s.match root
app.config.paths["db/migrate"] << File.join(root, 'db/migrate')
end
end
There is no need to copy migrations from your gem with generators if you use this technique.
You can make a method to yield the root directory of your gem with some thing like this...
module MyGemName
def root
File.expand_path '../..', __FILE__
end
module_method :root
end
... in the file lib/my_gem_name.rb in your gem.
I do not know of a very clean way to do it, but the code that runs migrations looks something like:
#migrations ||= begin
files = Dir["#{#migrations_path}/[0-9]*_*.rb"]
migrations = files.inject([]) do |klasses, file|
version, name = file.scan(/([0-9]+)_([_a-z0-9]*).rb/).first
Where,
#migrations_path = 'db/migrate'
So if you change this to read from config file instead, it may work out in your favour. But as I said, this is definitely not a very clean way to do it.
Just add this initializer to your lib/engine.rb:
initializer 'your_engine_name.migrations' do |app|
config.paths['db/migrate'].expanded.each do |expanded_path|
app.config.paths['db/migrate'] << expanded_path
ActiveRecord::Migrator.migrations_paths << expanded_path
if Rake.application.top_level_tasks.empty?
ActiveRecord::Migration.check_pending! if ActiveRecord::Migrator.needs_migration?
end
end
end