LoadError in StoreController#add_to_cart - ruby-on-rails

I am trying to learn Ruby on Rails using Agile Web Development with Rails third edition and I am completely stuck. I am using Ruby version 1.8.7 and rails 2.3.5 on Linux Mint. Just after the book recommended that I change from cookies to the SQLite database to manage sessions, the application no longer works. I get the following error when I click on the “add to cart” button in http://localhost:3000/store:
LoadError in StoreController#add_to_cart
Expected /home/dave/work/depot/app/models/cart.rb to define Cart
RAILS_ROOT: /home/dave/work/depot
Application Trace | Framework Trace | Full Trace
/usr/lib/ruby/1.8/active_support/dependencies.rb:426:in load_missing_constant'
/usr/lib/ruby/1.8/active_support/dependencies.rb:80:inconst_missing'
/usr/lib/ruby/1.8/active_support/dependencies.rb:92:in const_missing'
/usr/lib/ruby/1.8/active_support/dependencies.rb:437:inload_missing_constant'
/usr/lib/ruby/1.8/active_support/dependencies.rb:96:in const_missing'
/home/dave/work/depot/app/controllers/store_controller.rb:14:infind_cart'
/home/dave/work/depot/app/controllers/store_controller.rb:8:in `add_to_cart'
Request
Parameters:
{"authenticity_token"=>"38s45mRICYPJ7dw+z/rlcBnQN7T8ZwfEThzUTFUrjeM=",
"id"=>"3"}
Show session dump
Response
Headers:
{"Content-Type"=>"",
"Cache-Control"=>"no-cache"}
def add_product(product)
current_item = #items.find {|item| item.product == product}
if current_item
current_item.increment_quantity
else
#items << CartItem.new(product)
end
end
I have done a search on this in Google and a similar error seems to be related to utf-8 encoding. I used Gedit to save the file as Western (ISO 8859-15) encoding and it made no difference. I have also retyped the programs in Vi to no avail. Each time I have made a change, I have stopped and restarted the server and also entered db:sessions:clear into a terminal.
I'm stumped. Any ideas?

This error tends to occur when there is an error in the file being loaded. One way to figure this out is to run:
ruby script/console
... then:
Cart
This should either load up the model OK, or output a more useful error.

Check your app/models/cart.rb , it should be like this
class Cart < ActiveRecord::Base
#stuff here
end
make sure its that.

Related

Multiple rails requests leads to uninitialized constant

I have a very simple set up where I make an API call, which calls a function, which will initialize an instance of a class. Weirdly, it works the first time, but any additional attempts to refresh the page gives me an uninitialized constant error for the very class being initialized. Here's an example
Rails 3.1
Ruby 2.0
in app/controllers/static_pages_controller.rb
class StaticPagesController < ApplicationController
require_relative 'test.rb'
def about
build_fleet()
render text: "This worked"
end
end
and in my app/controllers/test.rb:
class Fleet
def initialize(side)
#ships = []
#passive_abilities = []
#side = side
end
end
def build_fleet()
att_fleet = ::Fleet.new("att")
def_fleet = ::Fleet.new("def")
end
I go to localhost/static_pages/about and get "This worked". Hit refresh and see "Fleet uninitialized" complete with the appropriate fleet stack.
When I check the server log I see
>Started GET "/static_pages/about" for 127.0.0.1 at 2014-04-05 15:52:39 -0700
> Processing by StaticPagesController#about as HTML
>Completed 500 Internal Server Error in 4ms
>
>NameError (uninitialized constant Fleet):
> app/controllers/test.rb:10:in `build_fleet'
> app/controllers/static_pages_controller.rb:4:in `about'
What's going wrong on the reload?
This seems related to how rails in development mode tries to automatically reload code on each request.
Try the advice in this answer and replace the call to require_relative with require_or_load "./test.rb"
*Edit: *
I think what's happening is that at the end of every request in development mode, rails undefines most constants it knows about. (Classes are constants.)
The next request comes in and you ask ruby to load the file. But since this second request is part of the same process, ruby remembers that it already loaded test.rb and so it is skipped.
However, it looks like Fleet is a model (even if not a database-backed model). I'd drop it in the app/models/fleet.rb and rails will auto load it just fine.

How do I call the Rails console's reload! command programmatically?

When using the Rails console, there's a handy reload! function which reloads models and such. How do I call this from another part of my program?
Edit I've been asked for the use case a bit. It was that I had a long running JVM process running Jruby and a clojure repl. I could run RSpec tests from the REPL and could run arbitrary Ruby code from there too. But I couldn't figure out how to reload the Ruby classes so that I could edit the code and see it changed in the Ruby runtime. I no longer use this setup, principally because testing it was such a pain.
(I'm using Jruby and can access the Ruby VM programatically from my backend).
Have you tried touching restart.txt? Unfortunately, I have no experience with JRuby, but confirmed it works on my app.
FileUtils.touch('tmp/restart.txt')
You probably want to do something other than a Get request, and secure it behind some authentication.
I threw it in an Admin controller and added the route to config/routes.
# app/controllers/admin.rb
class AdminController < ApplicationController::Base
##time = Time.now # This value gets cached with the model.
def reboot
FileUtils.touch('tmp/restart.txt')
#restarted_time = ##time
end
end
# config/routes.rb
namespace :admin
get 'reboot'
end
# app/views/admin/reboot.html.erb
<%= #restarted_time.to_s %>

Active Merchant - uninitialized constant ActiveSupport::XmlMini_REXML::StringIO

I have activemerchant 1.16.0 and rails 3.0.5.
I am trying to build a basic code to communicate with PayPal's gateway using active merchant.
if credit_card.valid?
# or gateway.purchase to do both authorize and capture
response = gateway.authorize(1000, credit_card, :ip => "127.0.0.1")
if response.success?
gateway.capture(1000, response.authorization)
puts "Purchase complete!"
else
puts "Error: #{response.message}"
end
else
puts "Error: credit card is not valid. #{credit_card.errors.full_messages.join('. ')}"
end
I get the following error:
/Library/Ruby/Gems/1.8/gems/activesupport-3.0.9/lib/active_support/xml_mini/rexml.rb:20:in `parse': uninitialized constant ActiveSupport::XmlMini_REXML::StringIO (NameError)
This error propagates from the gateway.authorize() call.
Any idea what's wrong with my setup?
Thanks.
According to the question, it doesn't work when the code is by itself, but works when require "stringio" is added.
My suspicion is that ActiveMerchant is unit-tested, but for some reason the dependency on StringIO isn't detected by those unit tests, possibly because other parts of the unit testing code indirectly requires stringio.
One thing I recently found out was that require 'yaml' gives you the stringio library as a side effect:
StringIO.new
# NameError: uninitialized constant StringIO
# from (irb):1
require "yaml"
# => true
StringIO.new
# => #<StringIO:0x7fb7d48ce360>
RUBY_VERSION
# => "1.8.7"
and it wouldn't be hard to imagine unit tests for ActiveMerchant (or other parts of Rails) requiring yaml.
However, this is only speculation. I haven't checked, as I don't use Rails.
Andrew Grimm pretty much hit the nail on the head with his original comment on this question. The missing require 'stringio' is indeed the issue. But it is a bug with Rails, more specifically ActiveSupport 3.0.9 (which is where the error seems to be coming from). We can trace it down using the git commit history of rails.
First we need to check out rails and switch to the v3.0.9 tag. If we now look at activesupport/lib/active_support/xml_mini/rexml.rb we see that require 'stringio' is not there. In and of itself this is not significant, but bear with me. We can now switch to the next tag (v3.0.10.rc1), and we'll see that the file hasn't been updated (it is likely that this version of rails will have the same issue). Next tag in line is v3.1.0.beta1, notice that this time around there is a require 'stringio' at the top of the file.
We can check out the commit that brought in this change (this one here from Jan 19th 2011). The commit message says:
fixed a missing require that causes trouble when using AS in a
non-rails env
This would indicate that as long as you're in a rails environment this issue wouldn't surface. So, my guess is something about the environment caused the issue to come up, may have something to do with the fact that the OP says they are using rails 3.0.5, but the error is coming from activesupport-3.0.9. Perhaps the code was called from a rake task that forgot to inherit from :environment (difficult to say without more info). Either way, putting require 'stringio' at the top of the code is definitely the fix, until you can upgrade to Rails 3.1 (once it comes out) at which point the require will no longer be needed.

Delayed_Job scraper works in development but not on Heroku

Here's the code for the scraper
class Scrape
def perform
url = "# a long url"
agent = Mechanize.new
agent.get(url)
while(agent.page.link_with(:text => "Next Page \u00BB")) do
agent.page.search(".content").each do |item|
puts "."
House.create!({
# attributes...
})
end
agent.page.link_with(:text => "Next Page \u00BB").click
end
end
end
On my local environment I can run it in the rails console just by typing
Scrape.new.delay.perform # to queue the job
rake jobs:work
and it works perfectly.
However running the analogous (with a worker running instead of rake jobs:work) in the Heroku console doesn't seem to do anything. I tried logging some lines in the Heroku log and I can get the url variable to log (so the method is at least getting called) but the "." which is there to show each time we run the while loop never appears and no Houses are created in the database.
Anyone any ideas what might be wrong?
Solved this problem myself, pretty obscure bug though. I was using ruby 1.9.2 in my local environment but I had the app deployed on a ruby 1.8.7 stack.
The important difference being the change in character encoding between the two ruby versions which meant that Mechanize couldn't find a link with the unicode encoded character "\u00BB" and thus didn't do any scraping.

How can I override a method in a ConnectionAdapter class in Rails 3 for use in a rake task?

In order to override the table_exists? method in the Rails PostgreSQL adapter I have tried the following in an initializer file:
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
def table_exists?(name)
raise 'got here'
end
end
This will raise the the following error:
uninitialized constant ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
I believe this would have worked in previous versions of rails and I even found a small plugin that did something like this in Rails 2.3.6. Also I only encounter this error when I am trying to run a rake task like db:migrate and not when I start my application server.
Could someone show me the right way to do this and / or explain why PostgreSQLAdapter doesn't seem to be loaded when I am in an initializer file?
Instead of config/initializers, place that code in lib/ folder.
While this means that the active_record is loaded after the rails initializers, which is unusual. I ll update this with more detail, once I am done investigating the whole flow. If you want some more details about the rails 3 initialization process, check out this link:
http://ryanbigg.com/guides/initialization.html
I had success by moving this code into a Rails plugin. It is a little bit more overhead, but it is working consistently when I run rails s and when I run rake db:migrate.
I just followed the rails guide page on the topic and ran
rails generate plugin rails_patches --with-generator
and moved my init.rb file into rails as recommended.
~vendor/
`~plugins/
`~rails_patches/
|~lib/
| `-rails_patches.rb
|~rails/
| `-init.rb
|+test/
|-install.rb
|-MIT-LICENSE
|-Rakefile
|-README
`-uninstall.rb
I put this code in init.rb:
require 'rails_patches'
I put this code in rails_patches.rb:
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.class_eval do
def table_exists?(name)
raise 'got here'
end
end
This now behaves as I expected.

Resources