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

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.

Related

undefined method '<=' for nil:NilClass 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?

Test helpers with RSpec in Padrino (Sinatra)

I'm trying to test a helper in a Padrino (Sinatra) app. My helper method is itself calling Padrino core helper methods but they are undefined. The error appears only in RSpec, while the app works fine. So the way I'm including my helper in RSpec makes it loose "Padrino scope" but I don't know how to bring Padrino helper's scope properly in my RSpec environment.
My helper:
module AdminHelper
Sort = Struct.new(:column, :order)
def sort_link(model, column)
order = sorted_by_this?(column) ? 'desc' : 'asc'
link_to mat(model, column), url(:pages, :index, sort: column, order: order)
end
def sorted_by_this?(column)
column.to_s == #sort.column && #sort.order == 'asc'
end
end
Lenstroy::Admin.helpers AdminHelper
My spec:
describe AdminHelper do
before(:all) do
class AdminHelperClass
include AdminHelper
end
end
subject(:helper) { AdminHelperClass.new }
describe '#sort_link' do
context "with :pages and :title parameters" do
before do
sort = AdminHelperClass::Sort.new('title', 'asc')
helper.instance_variable_set('#sort', sort)
end
subject { helper.sort_link(:pages, :title) }
it { should match(/<a href=([^ ]+)pages/) }
end
end
end
Results in error:
1) AdminHelper#sort_link with :pages and :title parameters
Failure/Error: subject { helper.sort_link(:pages, :title) }
NoMethodError:
undefined method `mat' for #<AdminHelperClass:0x007f1d951dc4a0>
Including a helper where mat is defined doesn't work, as one method is dependent on another helper and it goes on and on...
Update
In my spec helper I have:
def app(app = nil, &blk)
#app ||= block_given? ? app.instance_eval(&blk) : app
#app ||= Lenstroy::Admin
#app.register Padrino::Helpers
#app.register Padrino::Rendering
#app
end
in my spec I have:
it "returns link to resource with sort parameters" do
app do
get '/' do
sort_link(:pages, :title)
end
end
get "/"
last_response.body.should =~ /<a href=([^ >]+)pages/
end
And now tests fail, last_response.body is ''.
Method #mat is defined in Padrino::Admin::Helpers::ViewHelpers. You can do
class AdminHelperClass
include Padrino::Admin::Helpers::ViewHelpers
include AdminHelper
end
Update:
If your methods are really dependent on all these routes and helpers you should consider doing full mockup of your app like this:
def mock_app(base=Padrino::Application, &block)
#app = Sinatra.new(base, &block)
#app.register Padrino::Helpers
#app.register Padrino::Rendering
# register other things
end
def app
Rack::Lint.new(#app)
end
mock_app do
get '/' do
sort_link(my_model, my_column)
end
end
get "/"
assert_equal "some test text", body
Here's how it's done in padrino-admin: https://github.com/padrino/padrino-framework/blob/master/padrino-admin/test/test_admin_application.rb
I was having the same problem (and getting very frustrated tracking down the modules and including them). So far, I've got my specs working by:
1) Explicitly defining my module (as explained in how to use padrino helper methods in rspec)
module MyHelper
...
end
MyApp::App.helpers MyHelper
2) Automatically including helpers at the top of my spec. (Right now I only have one helper spec, but in the future I might try to move this into spec_helper.rb.)
describe MyHelper do
let(:helpers) { Class.new }
before { MyApp::App.included_modules.each { |m| helpers.extend m } }
subject { helpers }
it 'blah' do
expect(subject.helper_method).to eq 'foo'
end
end

Mock current_account on Padrino for rspec test

I'm trying to test a padrino controller that depends on current_account provided by Padrino::Admin::AccessControl
To do so, I need to mock current_account.
the code is something like:
App.controller :post do
post :create, map => '/create' do
Post.create :user => current_account
end
end
and the rspec:
describe "Post creation" do
it 'should create' do
account = Account.create :name => 'someone'
loggin_as account #to mock current_account
post '/create'
Post.first.user.should == account
end
end
How can I implement "loggin_as" or how can I write this test?
I found a simple way to test:
App.any_instance.stub(:current_account).and_return(account)
So, the test code should be:
describe "Post creation" do
it 'should create' do
account = Account.create :name => 'someone'
App.any_instance.stub(:current_account).and_return(account)
post '/create'
Post.first.user.should == account
end
end
but I still like to build "loggin_as" helper. So, how can I dynamically get App class? (should I create another thread for this question?)

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

You have a nil object when you didn't expect it

I’m interested in the topic of Rails security and using Security on Rails. I'm on Implementing RBAC /page 142/ and i cannot get past the error in the subject.
Here is the code:
module RoleBasedControllerAuthorization
def self.included(base)
base.extend(AuthorizationClassMethods)
end
def authorization_filter
user = User.find(:first,
:conditions => ["id = ?", session[:user_id]])
action_name = request.parameters[:action].to_sym
action_roles = self.class.access_list[action_name]
if action_roles.nil?
logger.error "You must provide a roles declaration\
or add skip_before_filter :authorization_filter to\
the beginning of #{self}."
redirect_to :controller => 'root', :action => 'index'
return false
elsif action_roles.include? user.role.name.to_sym
return true
else
logger.info "#{user.user_name} (role: #{user.role.name}) attempted to access\
#{self.class}##{action_name} without the proper permissions."
flash[:notice] = "Not authorized!"
redirect_to :controller => 'root', :action => 'index'
return false
end
end
end
module AuthorizationClassMethods
def self.extended(base)
class << base
#access_list = {}
attr_reader :access_list
end
end
def roles(*roles)
#roles = roles
end
def method_added(method)
logger.debug "#{caller[0].inspect}"
logger.debug "#{method.inspect}"
#access_list[method] = #roles
end
end
And #access_list[method] = #roles line throwing following exception:
ActionController::RoutingError (You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.[]=):
app/security/role_based_controller_authorization.rb:66:in `method_added'
app/controllers/application_controller.rb:5:in `<class:ApplicationController>'
app/controllers/application_controller.rb:1:in `<top (required)>'
app/controllers/home_controller.rb:1:in `<top (required)>'
I'm using Rails 3.0.3 and Ruby 1.9.2. I'm storing session in database. In finally thank you for every advise.
It seems like you can't access #access_list in method_added. I would try
class << base
attr_accessor :access_list
#access_list = {}
end
Might not solve your particular problem, but otherwise you won't be able to call #access_list[method] = #roles if your access_list attribute is read-only.
I'm not sure if this is the problem, but this looks suspicious:
class << base
#access_list = {}
attr_reader :access_list
end
Shouldn't #access_list be a class variable ##access_list?
Your defining #access_list as a instance variable of the class but your accessing it in as a instance_variable of an instance of the class. The following should probably work:
module AuthorizationClassMethods
def access_list
#access_list ||={}
end
def method_added(method)
logger.debug "#{caller[0].inspect}"
logger.debug "#{method.inspect}"
access_list[method] = #roles
end
end
If you need Auhorization you might want to check out Cancan by Ryan Bates
https://github.com/ryanb/cancan

Resources