undefined method '<=' for nil:NilClass Ruby - ruby

I have a Ruby model Book.rb that has the following:
class Book < Library
field :name
field :checked_out, default: false
field :checked_in, default: true
def checked_out?
checked_out && !checked_in
end
def checked_in?
checked_in && !checked_out
end
Then, in my index.haml file, have the following:
-#books.each do |book|
haml :"books/list_all" locals: {book: book}
Finally, in my list_all.haml file, I have:
.h4
#{book.name}
- if "#{book.checked_in?}"
Book is checked in
- else
Book is checked out
Update: book_routes.rb
get '/' do
haml :'books/index'
end
However, I get a undefined method <= for nil:NilClass error. How can I fix this?

Related

undefined method `original_filename' for #<CarrierWave::Storage::AWSFile:

Can't seem to identify why I would be getting a undefined method original_filename.
Maybe because when upgrading ruby 3.1.2,with ruby 2.7.5 can still use this method.
Uploader
class DocumentUploader < CarrierWave::Uploader::Base
CarrierWave::SanitizedFile.sanitize_regexp = Settings.regex.upload_filename
def store_dir
"uploads/event_documents/#{mounted_as}/#{model.id}"
end
end
Model
class EventDocumentFile < ActiveRecord::Base
mount_uploader :document_file, DocumentUploader
validate :document_file_name
private
def document_file_name
return if !document_file.file.present? || document_file.file.original_filename.length <= 70
errors.add :document_file, I18n.t("event_documents.invalid_file_name")
end
end
Error detail
undefined method `original_filename' for #<CarrierWave::Storage::AWSFile:0x00007fe60dfc38e8 #uploader=#<DocumentUploader:0x00007fe60dfbdc18 #model=#<EventDocumentFile
return if !document_file.file.present? || document_file.file.original_filename.length <= 70
^^^^^^^^^^^^^^^^^^
Anyone know what's wrong with my code? thanks!

Ruby - Error: undefined method `[]' for nil:NilClass

So, I'm new to Ruby and I'm trying to install this photo gallery to my Jekyll blog. However, when I'm trying to run
jekyll build
I get this error message:
Liquid Exception: undefined method `[]' for nil:NilClass in photography/index.html
jekyll 3.7.2 | Error: undefined method `[]' for nil:NilClass
With --trace it points me to:
/Users/hal9000/Desktop/Plommonstop/_plugins/jekyll-exiftag-mod.rb:18:in `render': undefined method `[]' for nil:NilClass (NoMethodError)
But now I don't understand how to proceed. jekyll-exiftag-mod looks like this:
require 'exifr/jpeg'
#Based on https://github.com/benib/jekyll-exiftag by Beni Buess (MIT License)
#Edited to work as a Liquid-Block instead of a Liquid-Tag, reads the filename from between the
#brackets. --T.Winter
module Jekyll
class ExifTag < Liquid::Block
def initialize(tag_name, params, token)
super
#args = self.split_params(params)
end
def render(context)
#abort context.registers[:site].config['source'].inspect
sources = Array.new(context.registers[:site].config['exiftag']['sources'])
# first param is the exif tag
tag = #args[0]
# if a second parameter is passed, use it as a possible img source
if #args.count > 1
sources.unshift(#args[1])
end
# the image can be passed as the third parameter
img = super
# first check if the given img is already the path
if File.exist?(img)
file_name = img
else
# then start testing with the sources from _config.yml
begin
source = sources.shift
file_name = File.join(context.registers[:site].config['source'], source, img)
end until File.exist?(file_name) or sources.count == 0
end
# try it and return empty string on failure
begin
exif = EXIFR::JPEG::new(file_name)
return tag.split('.').inject(exif){|o,m| o.send(m)}
rescue
"ERROR, EXIF-Tag RB"
end
end
def split_params(params)
params.split(",").map(&:strip)
end
end
end
Liquid::Template.register_tag('exiftag', Jekyll::ExifTag)
With row 18:
sources = Array.new(context.registers[:site].config['exiftag']['sources'])
What does it mean with "Undefined method `[]' for nil:NilClass?" And what exactly is making this problem occur?
The error could simply mean that you have not set ['exiftag']['sources'] in your config file.
Your config file should have something similar to below (entry1 and entry2 are just examples):
exiftag:
sources:
- entry1
- entry2
Do note, indentation is important in YAML as well..

Failure/Error: get :index NoMethodError: undefined method `<=' for nil:NilClass

I hope this is not a specific error and it may be a logic error that can help others as well.
I want to test my controller index method, and i have a before method with an active record query. The problem is that i can't figure what is wrong with my test because i get this error only when using rspec and not when i test it manually.
Controller
class BlogsController < ApplicationController
before_filter :archive_months
def archive_months
#months = Blog.find(:all, :select=>:publish_date, :order=>"publish_date DESC")
.select{ |p| p.publish_date <= Date.today }
.group_by{ |p| [p.year, p.month, p.publish_date.strftime("%B")] }
end
Test
require 'rails_helper'
RSpec.describe BlogsController, :type => :controller do
before(:each) do
#post1 = create(:blog)
end
describe "GET #index" do
it "shows all blog posts" do
get :index
expect(response).to have_http_status(200)
end
end
end
Test output
1) BlogsController GET #index shows all blog posts
Failure/Error: get :index
NoMethodError:
undefined method `<=' for nil:NilClass
# ./app/controllers/blogs_controller.rb:178:in `block in archive_months'
# ./app/controllers/blogs_controller.rb:177:in `select'
# ./app/controllers/blogs_controller.rb:177:in `archive_months'
If i run the #months query on the page or in rails console it works well, but on my test in does not work.
It seems you have one or more Blog objects in your test database that don't have a publish_date attribute set. That's why .select{ |p| p.publish_date <= Date.today } raises the error.

riak content_type no method error

I have the 4 node riak setup running on my os x machine. I have the following program -
require 'riak'
class RiakClient < Riak::Client
#attr_accessor :bucket
def initialize(hosts="")
return Riak::Client.new(:nodes => [{:http_port => 8091},{:http_port =>8092},{:http_port=>8093},{:http_port =>8094}])
end
def get_me(bucket, key)
obj = self.bucket(bucket).get(key)
puts obj.data
end
def put_me(bucket, key, data, content_type)
obj=self.bucket(bucket).get_or_new(key)
puts obj.class
obj.content_type=content_type
obj.raw_data=data
obj.store
end
end
if __FILE__ == $0
my_client=RiakClient.new
my_client.put_me("doc", "index.html", "some data goes here", "text/html")
hash=my_client.get_me("doc", "index.html")
end
I am getting the following error
NilClass
riak_client.rb:32:in `put_me': undefined method `content_type=' for nil:NilClass (NoMethodError)
from riak_client.rb:42:in `<main>'
Do I have to import the RiakBucket and RiakObject classes? It seems that the RiakBucket methods cannot be accessed here?
The actual question here is: why does get_or_new return nil?
It's probably because your initialize() method returns a new Riak::Client, but the Riak::Client that is your parent object never gets initialized. Try putting a call to super instead of the return Riak::Client.new in initialize.
Subclassing Riak::Client is a bit dubious here. I would tend to delegate to it instead.

Having 'allocator undefined for Data' when saving with ActiveResource

What I am missing? I am trying to use a rest service for with Active resource, I have the following:
class User < ActiveResource::Base
self.site = "http://localhost:3000/"
self.element_name = "users"
self.format = :json
end
user = User.new(
:name => "Test",
:email => "test.user#domain.com")
p user
if user.save
puts "success: #{user.uuid}"
else
puts "error: #{user.errors.full_messages.to_sentence}"
end
And the following output for the user:
#<User:0x1011a2d20 #prefix_options={}, #attributes={"name"=>"Test", "email"=>"test.user#domain.com"}>
and this error:
/Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb:1233:in `new': allocator undefined for Data (TypeError)
from /Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb:1233:in `load'
from /Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb:1219:in `each'
from /Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb:1219:in `load'
from /Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb:1322:in `load_attributes_from_response'
from /Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb:1316:in `create_without_notifications'
from /Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb:1314:in `tap'
from /Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb:1314:in `create_without_notifications'
from /Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/active_resource/observing.rb:11:in `create'
from /Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb:1117:in `save_without_validation'
from /Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/active_resource/validations.rb:87:in `save_without_notifications'
from /Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/active_resource/observing.rb:11:in `save'
from import_rest.rb:22
If I user curl for my rest service it would be like:
curl -v -X POST -H 'Content-Type: application/json' -d '{"name":"test curl", "email":"test#gmail.com"}' http://localhost:3000/users
with the response:
{"email":"test#gmail.com","name":"test curl","admin":false,"uuid":"afb8c98b-562a-4603-bbe4-f8f0816cef0d","creation_limit":5}
There is a built-in type named Data, whose purpose is rather mysterious. You appear to be bumping into it:
$ ruby -e 'Data.new'
-e:1:in `new': allocator undefined for Data (TypeError)
from -e:1
The question is, how did it get there? The last stack frame puts us here. So, it appears Data wandered out of a call to find_or_create_resource_for. The code branch here looks likely:
$ irb
>> class C
>> end
=> nil
>> C.const_get('Data')
=> Data
This leads me to suspect you have an attribute or similar floating around named :data or "data", even though you don't mention one above. Do you? Particularly, it seems we have a JSON response with a sub-hash whose key is "data".
Here's a script that can trigger the error for crafted input, but not from the response you posted:
$ cat ./activeresource-oddity.rb
#!/usr/bin/env ruby
require 'rubygems'
gem 'activeresource', '3.0.10'
require 'active_resource'
class User < ActiveResource::Base
self.site = "http://localhost:3000/"
self.element_name = "users"
self.format = :json
end
USER = User.new :name => "Test", :email => "test.user#domain.com"
def simulate_load_attributes_from_response(response_body)
puts "Loading #{response_body}.."
USER.load User.format.decode(response_body)
end
OK = '{"email":"test#gmail.com","name":"test curl","admin":false,"uuid":"afb8c98b-562a-4603-bbe4-f8f0816cef0d","creation_limit":5}'
BORKED = '{"data":{"email":"test#gmail.com","name":"test curl","admin":false,"uuid":"afb8c98b-562a-4603-bbe4-f8f0816cef0d","creation_limit":5}}'
simulate_load_attributes_from_response OK
simulate_load_attributes_from_response BORKED
produces..
$ ./activeresource-oddity.rb
Loading {"email":"test#gmail.com","name":"test curl","admin":false,"uuid":"afb8c98b-562a-4603-bbe4-f8f0816cef0d","creation_limit":5}..
Loading {"data":{"email":"test#gmail.com","name":"test curl","admin":false,"uuid":"afb8c98b-562a-4603-bbe4-f8f0816cef0d","creation_limit":5}}..
/opt/local/lib/ruby/gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb:1233:in `new': allocator undefined for Data (TypeError)
from /opt/local/lib/ruby/gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb:1233:in `load'
from /opt/local/lib/ruby/gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb:1219:in `each'
from /opt/local/lib/ruby/gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb:1219:in `load'
from ./activeresource-oddity.rb:17:in `simulate_load_attributes_from_response'
from ./activeresource-oddity.rb:24
If I were you, I would open /Library/Ruby/Gems/1.8/gems/activeresource-3.0.10/lib/active_resource/base.rb, find load_attributes_from_response on line 1320 and temporarily change
load(self.class.format.decode(response.body))
to
load(self.class.format.decode(response.body).tap { |decoded| puts "Decoded: #{decoded.inspect}" })
..and reproduce the error again to see what is really coming out of your json decoder.
I just ran into the same error in the latest version of ActiveResource, and I found a solution that does not require monkey-patching the lib: create a Data class in the same namespace as the ActiveResource object. E.g.:
class User < ActiveResource::Base
self.site = "http://localhost:3000/"
self.element_name = "users"
self.format = :json
class Data < ActiveResource::Base; end
end
Fundamentally, the problem has to do with the way ActiveResource chooses the classes for the objects it instantiates from your API response. It will make an instance of something for every hash in your response. For example, it'll want to create User, Data and Pet objects for the following JSON:
{
"name": "Bob",
"email": "bob#example.com",
"data": {"favorite_color": "purple"},
"pets": [{"name": "Puffball", "type": "cat"}]
}
The class lookup mechanism can be found here. Basically, it checks the resource (User) and its ancestors for a constant matching the name of the sub-resource it wants to instantiate (i.e. Data here). The exception is caused by the fact that this lookup finds the top-level Data constant from the Stdlib; you can therefore avoid it by providing a more specific constant in the resource's namespace (User::Data). Making this class inherit from ActiveResource::Base replicates the behaviour you'd get if the constant was not found at all (see here).
Thanks to phs for his analysis - it got me pointed in the right direction.
I had no choice but to hack into ActiveResource to fix this problem because an external service over which I have no control had published an API where all attributes of the response were tucked away inside a top-level :data attribute.
Here's the hack I ended up putting in config/initializers/active_resource.rb to get this working for me using active resource 3.2.8:
class ActiveResource::Base
def load(attributes, remove_root = false)
raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
#prefix_options, attributes = split_options(attributes)
if attributes.keys.size == 1
remove_root = self.class.element_name == attributes.keys.first.to_s
end
# THIS IS THE PATCH
attributes = ActiveResource::Formats.remove_root(attributes) if remove_root
if data = attributes.delete(:data)
attributes.merge!(data)
end
# END PATCH
attributes.each do |key, value|
#attributes[key.to_s] =
case value
when Array
resource = nil
value.map do |attrs|
if attrs.is_a?(Hash)
resource ||= find_or_create_resource_for_collection(key)
resource.new(attrs)
else
attrs.duplicable? ? attrs.dup : attrs
end
end
when Hash
resource = find_or_create_resource_for(key)
resource.new(value)
else
value.duplicable? ? value.dup : value
end
end
self
end
class << self
def find_every(options)
begin
case from = options[:from]
when Symbol
instantiate_collection(get(from, options[:params]))
when String
path = "#{from}#{query_string(options[:params])}"
instantiate_collection(format.decode(connection.get(path, headers).body) || [])
else
prefix_options, query_options = split_options(options[:params])
path = collection_path(prefix_options, query_options)
# THIS IS THE PATCH
body = (format.decode(connection.get(path, headers).body) || [])
body = body['data'] if body['data']
instantiate_collection( body, prefix_options )
# END PATCH
end
rescue ActiveResource::ResourceNotFound
# Swallowing ResourceNotFound exceptions and return nil - as per
# ActiveRecord.
nil
end
end
end
end
I solved this using a monkey-patch approach, that changes "data" to "xdata" before running find_or_create_resource_for (the offending method). This way when the find_or_create_resource_for method runs it won't search for the Data class (which would crash). It searches for the Xdata class instead, which hopefully doesn't exist, and will be created dynamically by the method. This will be a a proper class subclassed from ActiveResource.
Just add a file containig this inside config/initializers
module ActiveResource
class Base
alias_method :_find_or_create_resource_for, :find_or_create_resource_for
def find_or_create_resource_for(name)
name = "xdata" if name.to_s.downcase == "data"
_find_or_create_resource_for(name)
end
end
end

Resources