Rolify dynamic calls not run or recognized by heroku - ruby-on-rails

I am getting an error for using a function provided by a special configuration on Heroku even though it works fine on my machine.
Specifically, I am using the Rolify method is_admin? on user, which is made possible by a configuration setting in an initializer file.
So far with Heroku I have migrated the database again, restarted the app and refreshed the page multiple times for each. How can I get Heroku to run the configuration file like my local machine does every time I reset the local server?
Error:
ActionView::Template::Error (undefined method `is_admin?' for #<User:0x0000000524c8e0>):
2012-07-22T09:00:53+00:00 app[web.1]: 1: <% if current_user.is_admin? %>
Code:
# config/initializers/rolify.rb
Rolify.configure do |config|
config.use_dynamic_shortcuts
end
Well, I tried one more thing and it worked, but here it is just in case.

I ran $ heroku run rake db:reset and it worked again. Not sure why, but oh well.
Edit:
The issue is that if you call Rolify custom methods when the role does not exist yet in the database, it results in an error. To get around this, either seed your database with all of the roles you'll need, or better, do not use dynamic methods.
For example, instead of:
#user.is_admin? use #user.has_role?(:admin) and it will not break.

Related

Heroku throws error where local host does not

I have a rails app running on heroku. Locally everything works fine. However, upon pushing to heroku there is an error.
The logs state this:
app/controllers/orders_controller.rb:7:in `create'
ActiveRecord::UnknownAttributeError (unknown attribute: ammo_id):
Started POST "/orders?ammo_id=4" for 96.235.177.110 at 2014-08-09 00:03:09 +0000
I.e. that this is an error in my orders_controller on line 7. This is line 7:
#order = #cart.orders.build(ammo_id:params[:ammo_id])
Locally this run perfectly. However, on heroku it does not. I changed that line to:
#order = #cart.orders.build(:ammo_id => params[:ammo_id])
And now it works on heroku. So my question is, why does the first syntax not work on heroku? Does it have to do with versions?
Attributes
Having just answered another question like this, I'd say the problem is almost certainly to do with your Heroku DB not having the attributes it needs to run
The issue here is that your Rails development DB & Heroku production DB will be completely different, and as such, you need to make sure you have migrated your Heroku db as you have your local one
The way to fix it will be to run the following on your local machine:
$ heroku run rake db:migrate
--
Whenever Rails throws ActiveRecord::UnknownAttributeError - it means Rails does not have access to the particular attribute on your model class.
To understand this, you must remember that Rails is basically a series of classes which load with each request. These classes, as per the object-orientated structure, are populated by a series of attributes. These attributes, in the case of Rails, are pulled from the database -- meaning if your application cannot find specific attributes, it simply means the database doesn't have them
To fix this, you have to ensure you have the required columns present in your db. The most common instance of this issue is a lack of foreign_key in your various models
It might have to do with Database Migrations. Make sure you run heroku run rake db:migrate <your branch stuff here> after every push so that our schema updates to your new models.
Also,Your heroku may be defaulting to an older version of ruby. The => syntax for hashes was the default in older versions of ruby. But now {key: value} is a new acceptable format. Though this is very unlikely.

How can 'parse' be undefined for Time class in test environment, but not development or production?

I'm encountering a strange issue while running a test (Steak + Capybara) that requests a certain page where I get the error:
undefined method parse for Time:Class
The method call occurs in a Sunspot file called type.rb:
def value_to_utc_time(value)
if value.respond_to?(:utc)
value.utc
elsif value.respond_to?(:new_offset)
value.new_offset
else
begin
Time.parse(value.to_s).utc
rescue ArgumentError
DateTime.parse(value.to_s).new_offset
end
end
end
When I run my server in RAILS_ENV=test, I get the same error. When I run the server in development, everything is fine and dandy. This would seem to indicate that it's not just my test framework, but the whole test environment that's promoting this error.
The only info I could find online so far about Time.parse being undefined has been quite unhelpful, with most people saying that adding require 'time' will solve the problem.
My problems with this are twofold:
It's hacky
I've tried it in various places (in config/environments/test.rb, in the test file itself, etc.), and it just doesn't work.
If anyone has any ideas what is going on, I welcome them!
I figured it out! Someone had created another file called time.rb in the Rails app's test directory, so method calls on the Time class in the test environment were invoking that file rather than the actual Time class. I got the inspiration to check for this possibility from this Github issue thread

How to universally skip database touches when precompiling assets on Heroku

I'm deploying a Rails 3.1 app to Heroku's Cedar stack. With Heroku Cedar and Rails 3.1, you can compile the assets yourself locally, let Heroku compile them when you push (during "slug compilation"), or have them be compiled just-in-time while the app is running. I want to do the middle option, letting Heroku precompile the assets.
When Heroku runs the assets:precompile task, it errors with "could not connect to server" because the app is trying to connect to the database but no database is available at that stage of slug compilation. The lack of database connection is expected and unavoidable at this point. I'm looking for a way to move past it, because a database connection isn't crucial to asset precompilation.
The part of my app that's trying to connect to the database is Devise. There's a devise_for :users line in routes.rb that wants to look at the User model.
I could just write a rake task that stubs out devise_for and make it a prereq of assets:precompile. I think that would solve my problem, but I'm looking for a more universal solution that I could use on any Rails 3.1 app with this problem on Heroku.
Is there anything out there, or can you conceive of anything that silences database connection errors while still running the app enough to have route and asset path generation?
Obviously if an app needs to read/write data during startup, we can't stub that, but can we fake every ActiveRecord model automatically?
add this to config/application.rb
config.assets.initialize_on_precompile=false
took me a while to hunt this down... adding it to config/environments/*.rb did NOT work
UPDATE: It doesn't work with rails 4
Heroku now makes a labs flag available that'll make the runtime environment available during compilation time, which means your app will be able to successfully connect to your DATABASE_URL database.
First you need to install the labs plugin:
$ heroku plugins:install http://github.com/heroku/heroku-labs.git
then enable the user-env-compile labs feature:
$ heroku labs:enable user-env-compile --app your-app-name
For me the problem is activerecord calling instantiate_observer in lib/active_record/railtie.rb:92. This will load the observers and the respective models. has_and_belongs_to_many then connects to the db.
I think I'll override this method when ENV["RAILS_ASSETS_PRECOMPILE"] is present, which is used by devise in the fix Bradley linked to.
EDIT: So this snippet fixed it for me:
namespace :assets do
# Prepend the assets:precompile_prepare task to assets:precompile.
task :precompile => :precompile_prepare
# This task will be called before assets:precompile to optimize the
# compilation, i.e. to prevent any DB calls.
task 'precompile_prepare' do
# Without this assets:precompile will call itself again with this var set.
# This basically speeds things up.
ENV['RAILS_GROUPS'] = 'assets'
# Devise uses this flag to prevent connecting to the db.
ENV['RAILS_ASSETS_PRECOMPILE'] = 'true'
# Prevent loading observers which will load the models which in turn may hit
# the DB.
module ActiveModel::Observing::ClassMethods
def instantiate_observers; end
end
# Prevent route drawing because certain gems might get called which will hit
# the DB.
class ActionDispatch::Routing::RouteSet
def draw; end
end
end
end
Workaround for Rails (4.2 edge):
Add the following as /config/initializers/precompile.rb:
module Precompile
# Public: ignore the following block during rake assets:precompile
def self.ignore
unless ARGV.any? { |e| e == 'assets:precompile' }
yield
else
line = caller.first
puts "Ignoring line '#{line}' during precompile"
end
end
end
and use it in your routes.rb like this:
Precompile.ignore { ActiveAdmin.routes(self) }
EDIT: This answer is out of date and no longer works - See fringd's answer.
Not quite a universal stubbing but devise has added a check now to fix this particular problem . See the issue and fix on Github. By providing a RAILS_ASSETS_PRECOMPILE environment config devise should skip building the routes
I stuck this in 'lib/tasks/assets.rake' and was able to get assets:precompile to actually succeed. This should work as long as you don't actually access the database as a result of requiring your environment. It obviously won't help with ActiveRecord, but it should work for all mongoid-based apps.
task 'assets:precompile' => 'assets:stub_mongoid'
task 'assets:stub_mongoid' do
def Mongoid.load!(*args)
true
end
end
Heroku added an unofficial flag to make the environment (i.e. also the DB) accessible during precompilation. Just ask them to switch it on and DB dependencies during asset precompilations are no longer an issue. Not sure, if/when this flag is officially available though, or if it will simply be the new default.
Spork.trap_method is also an interesting solution to the problem of Devise's routes_for calling the model early in the load process. Solution can't be applied directly AFAIK, but it's solving the same sort of problem, so it might provide inspiration for somebody.
Spork.trap_method
I lack sufficient reputation to comment, so here's another answer.
It's true that #fringd's top-rated answer does not work on Rails 4. I have, however, found this technique to work:
https://iprog.com/posting/2013/07/errors-when-precompiling-assets-in-rails-4-0
Although, I rearranged the BASH variables like so:
~$ RAILS_ENV=production DATABASE_URL=postgresql://user:pass#127.0.0.1/dbname bundle exec rake assets:precompile
BTW, This is a fantastic aid if you need to build a Docker image. Put that line into your Dockerfile so your DB can live in a different container and your app containers don't need to precompile assets every time they start up!
Disable AR:
config = Rails.application.config
def config.database_configuration
{}
end
ar = ActiveRecord::Base
def ar.establish_connection
end

Rails NoMethod Error when calling a dynamic attribute find

I am currently working on an app. In this app, I created a Person model and I was using rail's dynamic attribute find feature. In the Person model I have an attribute called uid, so I was calling Person.find_by_uid(some numerical value). This worked fine in my development mode and the app was totally functioning. However, once I deployed this app to heroku. The app failed and the log complains about NoMethodError (undefined method `find_by_uid' for #):
I have been looking all places, but still unable to track down the problem. I tried to define the method find_by_uid under the Person model, and still does not work.
I was wondering if anyone has had similar experience or knows how to solve this issue?
Thank you very much ahead of the time!
Did you try running the migrations in heroku (heroku rake db:migrate)? Most provably that attribute is not in the heroku data base so you don't have that dynamic method.
I ran into the same problem. heroku restart has saved me.

Rails staging environment says "undefined method" but the console shows that method fine

Anyone have this happen before? I just uploaded my app to a staging server that's identical to the production server. I try to log in, and I get the "Something went wrong" 500 page. The log tells me the error is in my SessionsController (using restful_authentication), with the specific error being NoMethodError (undefined method 'enabled?' for #<User:0xb6c5dbd4>):. I load up a console for my staging environment and pull back the user in question... and the enabled method is defined (calling user.enabled? returns the expected value, and not a no method error).
Anyone have any ideas? I've specified in Passenger that the RailsEnv should be staging; could it be that Passenger is not recognizing this? When I created my database and ran my migrations, I had to explicitly say RAILS_ENV=staging, otherwise it was trying to load the development data and throwing an error because my development box connects through a different MySQL socket than staging|production.
The enabled method is defined on my users table and therefore the User model. The code in the controller is something like this:
# SessionsController.rb
def create
user = User.authenticate(params[:username], params[:password)
if user
unless user.enabled?
note_disabled_account # basically prints a message
else
self.current_user = user
# other stuff
redirect_back_or_default('/')
end
end
end
The code is identical in Production and works fine, so the issue is something related to the fact that I created a "staging" environment.
EDIT: I've narrowed the error down to being some kind of caching issue, despite the fact I've restarted Passenger. We are using Amazon EC2 and the staging server was basically cloned from Production (so it had an older version of the application on it). For some reason when I am deploying from Capistrano and restarting Passenger, it does not seem to properly link to the new version; I tried removing the enabled line and I was able to log in, but pulling up a record gives me another undefined method - the method in question is something that was added after the Staging server was created.

Resources