ActiveRecord Concern spec fails when uses self.class - ruby-on-rails

I have next Siteable concern:
module Siteable
extend ActiveSupport::Concern
included do
belongs_to :site
scope :by_site, lambda { |site| where(site_id: site.try(:id)) }
scope :for_site, lambda { |site| by_site self.class.by_site(site).any? ? site : nil }
end
end
Example model with this concern:
class IndustryLink < LinkResource
require 'concerns/siteable.rb'
include Siteable
belongs_to :author, :class_name => 'User'
belongs_to :industry
validates_presence_of :name, :link
end
It work fine on the server. But all specs with this model fails with similar errors:
Failure/Error: industry = Factory(:industry, :name => 'new industry')
NoMethodError:
undefined method `by_site' for Class:Class
# ./app/models/concerns/siteable.rb:8:in `block (2 levels) in <module:Siteable>'
# ./app/models/industry_link.rb:12:in `get_objects'
# ./app/models/concerns/reorderable.rb:47:in `add_number'
# ./spec/views/sitemap/show.xml.builder_spec.rb:41:in `block (2 levels) in <top (required)>'
So, obviously that self.class is not Industry in this case and I don't know how to fix this.
If I move for_site to model and change self.class to Industry specs passes.
Checked for ruby 1.9.3, 2.1.1, Rails 3.2.19

Within your lambda self is already the model class - Industry, so the self.class is Class
You should just be using by_site (possibly unscoping it first, depending on what you need)

Related

How do disable email validation in Clearance

I'm trying to get Clearance to work with AWS Dynamo as the back-end store. The problem I'm having is that I can't get Clearance to not do the email-uniqueness validation, which it can't do because it's not able to do standard ActiveRecord uniqueness validations via a SQL query.
According to the comments in the code, I should be able to have my User object return email_optional? true, and that should disable the uniqueness validation on emails. So I have:
class User < ApplicationRecord
include Dynamoid::Document
include Clearance::User
field :name
field :email
def email_optional?
puts 'yes, email is optional'
true
end
end
But, when I try to create a user I get an error, and, more to the point, the puts is not executed:
$ rails c
Running via Spring preloader in process 18665
Loading development environment (Rails 5.1.3)
irb(main):001:0> u = User.new(name: 'ijd', email: 'ian#fu.bar', password: 'test')
ActiveRecord::StatementInvalid: Could not find table 'editor_development_users'
from (irb):1
Update: the reply from #spickermann reminded me that I should have noted that I also tried without subclassing ActiveRecord::Base (via ApplicationRecord). It gives a different error:
class User
include Dynamoid::Document
....
irb(main):002:0> reload!
Reloading...
=> true
irb(main):003:0> u = User.new(name: 'ijd', email: 'ian#fu.bar', password: 'test')
ArgumentError: Unknown validator: 'UniquenessValidator'
from app/models/user.rb:4:in `include'
from app/models/user.rb:4:in `<class:User>'
from app/models/user.rb:2:in `<top (required)>'
from (irb):3
User.new does not trigger validations. Therefore the error cannot be connected to the validations itself.
At the moment your User model is kind of both: A subclass of ActiveRecord::Base and it behaves like a Dynamoid::Document.
class User < ApplicationRecord
include Dynamoid::Document
# ...
end
ActiveRecord::Base reads the table definition from the database when an instance is initialized. This leads to your exception, because the table does not exist. Just remove the inheritance from ApplicationRecord.
class User
include Dynamoid::Document
# ...
end
The second issue when you remove the inheritance is more complex. Usually, I would suggest to just include ActiveModel::Validations when you want to validate models that do not inherit from ActiveRecord::Base. But the UniquenessValidator isn't defined in ActiveModel::Validations but in ActiveRecord::Validations (what makes kind of sense). This makes Clearance incompatible with models that do not inherit from ActiveRecord::Base.
I would probably define a dummy implementation of a UniquenessValidator as a work-around:
class User
include Dynamoid::Document
class UniquenessValidator
def initialize(_options); end
def def validate_each(_record, _attribute, _value); end
end
# ...
end

Rspec, testing object receives method

I have an example of code not passing in test but working in the console.
Failing Test:
describe ImporterProfile do
it 'sends defaults method to EventAttribute model' do
expect(ListPage).to receive(:new) #passes
expect(EventAttribute).to receive(:new) #fails
ImporterProfile.new.standard_profile
end
1) ImporterProfile standard_profile sends new method to associated objects
Failure/Error: importer_profile.standard_profile
NoMethodError:
undefined method `each' for nil:NilClass
# ./app/models/importer_profile.rb:51:in `standard_profile'
# ./spec/models/importer_profile_spec.rb:29:in `block (3 levels) in <top (required)>'
Models:
class ImporterProfile < ActiveRecord::Base
has_one :list_page, dependent: :delete
has_many :event_attributes, dependent: :delete_all
accepts_nested_attributes_for :list_page
accepts_nested_attributes_for :event_attributes
def standard_profile
self.list_page = ListPage.new
self.event_attributes = EventAttribute.new
end
end
class EventAttribute < ActiveRecord::Base
belongs_to :importer_profile
end
class ListPage < ActiveRecord::Base
belongs_to :importer_profile
end
However, running this method in the console instantiates a new ImporterProfile, ListPage and several EventAttribute objects.
Anyone understand what is going on here?
I suspect that the problem is that you are mocking EventAttribute.new, but only returning nil, so Rails can't enumerate the active records as is required by the self.event_attributes = statement. (It needs to set the foreign key attribute of the EventAttribute records to the id of the ImporterProfile record.)
If you don't mind continuing with execution, you can do:
expect(EventAttribute).to receive(:new).and_call_original
Alternatively, you can return a double, but you'll need to provide stubs for whatever methods ActiveRecord requires, either by using a library such as http://rubygems.org/gems/rspec-active_record_mocks/versions/0.1.4 or by rolling your own.
As an aside, this question would have been a little easier to answer if you'd provided some way to associate the line numbers in the error stack trace with the sources you provided. Also, the comments on your expect statements that the first passes and the second fails is confusing because it appears that you are raising an error before the expectations are being checked.

undefined method `column_names' for Module:Class

I wan't to test a has_many association on a class:
class Course < ActiveRecord::Base
has_many :modules
end
For this I wrote a test (Rspec):
describe Course do
it { should have_many(:modules) }
end
For some reason however this test fails:
1) Course should have many modules
Failure/Error: it { should have_many(:modules) }
NoMethodError:
undefined method `column_names' for Module:Class
# ./spec/models/course_spec.rb:4:in `block (2 levels) in <top (required)>'
Does someone has an idea why this test fails? I created a Module class:
class Module > ActiveRecord::Base
belongs_to :course
end
Could it be that 'Module' is a reserved keyword, and therefore I cannot create a class Module?
Thanks for your help,
Anthony
Module is "reserved" name in Ruby (since Ruby has build-in - and very important - Module class). This is probably source of your error.

Rspec Tests fail using custom model validation

I have this custom validation method which makes sure you can't vote on your own content, and it causes quite a few RSpec test to fail with undefined method 'user_id' for nil:NilClass
Is there a way to rewrite the custom validation, or use a native rails validation?
failing tests
12) Vote votable type
Failure/Error: #vote = FactoryGirl.create(:vote)
NoMethodError:
undefined method `user_id' for nil:NilClass
# ./app/models/vote.rb:18:in `ensure_not_author'
# ./spec/models/vote_spec.rb:5:in `block (2 levels) in <top (required)>'
validate :ensure_not_author
vote.rb
attr_accessible :value, :votable_id, :votable_type
belongs_to :votable, polymorphic: true
belongs_to :user
def ensure_not_author
votable = self.votable_type.downcase
errors.add(:user_id, "You can't vote on your own content.") if self.votable.user_id == self.user_id
end
if anyone needs more code just shout
it looks like self.votable is nil. It appears as though this test should view the vote from the votable's point of view. If that's the case, then create the vote in the factory for your votable and move the test to your votable entity's suite, as you're really testing that the votable should not be able to vote on its own content.

ActiveRecord model subclass NoMethodError on 'create'

I've got a Rails 4 beta app (on Ruby 2) and I'm getting an error I can't make sense out of.
I've got some specs that are failing because my model class has no method 'create', even though I'm inheriting from ActiveRecord::Base. The error message is calling my class a module (undefined method 'create' for Topic:Module), and that seems odd.
spec/models/topic_spec.rb:
require "spec_helper"
describe Topic do
it "should create a new topic given valid attributes" do
Topic.create!({:created_by_id => 1, :title => "Test" })
end
end
app/models/topic.rb
class Topic < ActiveRecord::Base
include ActiveModel::ForbiddenAttributesProtection
validates :title => :presence => ture
validates :created_by_id => :presence => true
end
Error message:
$ rspec spec/models/topic_spec.rb
F
Failures:
1) Topic should create a new topic given valid attributes
Failure/Error: Topic.create!({:created_by_id => 1, :title => "Test" })
NoMethodError:
undefined method `create' for Topic:Module
# ./spec/models/topic_spec.rrc:15:in `block (2 levels) in <top (required)>'
It sounds like you have a module or namespace also named Topic that is getting loaded first and so in your tests, Topic is not referring to your class. Are there any other files that have Topic in them, even something like class Topic::Question or similar? If so, try taking them out or being explicit about it. For example, changing:
class Topic::Question < ActiveRecord::Base
to
class Topic
class Question < ActiveRecord::Base

Resources