how to test rspec shoulda for custom validation in rails? - ruby-on-rails

I have a Private methods in my model like the following:
validate :record_uniq
private
def record_uniq
if record_already_exists?
errors.add(:base, "already exists")
end
end
def record_already_exists?
question_id = measure.question_id
self.class.joins(:measure).
where(measures: {question_id: ques_id}).
where(package_id: pack_id).
exists?
end
This methods is more like a uniqueness scope thing to prevent duplicate records. I want to know how to write test for validate :record_uniq by using shoulda or rspec?
Example of what i tried:
describe Foo do
before do
#bar = Foo.new(enr_rds_measure_id: 1, enr_rds_package_id: 2)
end
subject { #bar }
it { should validate_uniqueness_of(:record_uniq) }
end

Simple - build an object that fails the validation, validate it, and verify that the correct error message has been set.
For example (if you had a model named City):
it 'validates that city is unique' do
city = City.new # add in stuff to make sure it will trip your validation
city.valid?
city.should have(1).error_on(:base) # or
city.errors(:base).should eq ["already exists"]
end

Here's what I would do using RSpec 3 syntax.
it 'validates that city is unique' do
city = City.new('already taken name')
expect(city).to be_invalid
expect(city.errors[:base]).to include('already exists')
end

Related

Faking ActiveRecord::Associations::CollectionProxy with Mocha in Capybara (Rails)

I have a very simple data structure: a User has_many filters and a Filter belongs_to a user. For my tests, I am using Capybara, minitest-rails and mocha (no rspec).
I am struggling to adequately stub an ActiveRecord collection of Filters. This is what I have currently:
require 'test_helper'
class TestExample < Capybara::Rails::TestCase
let(:user) { FactoryGirl.create(:user) }
def setup
# Create some mock filters:
f1 = Filter.new
f1.stubs(:id).returns(1)
f1.stubs(:user_id).returns(1)
f1.stubs(:title).returns("First Filter")
f1.stubs(:value).returns(123)
f2 = Filter.new
f2.stubs(:id).returns(2)
f2.stubs(:user_id).returns(1)
f2.stubs(:title).returns("Second Filter")
f2.stubs(:value).returns(456)
fake_filters = [f1, f2]
user.stubs(:filters).returns(fake_filters)
end
def test_user_has_correct_number_of_mocked_filters
assert_equal(user.filters.count, 2)
end
def test_users_mocked_filters_have_correct_ids
assert_equal(user.filters.pluck(:id), [1, 2]) # ERROR
end
end
The second test throws an error, since their is no pluck() method for an Array.
How would this be accomplished? I want the tests to behave as if there are indeed records in the Filter table.
You really shouldn't be mocking objects when using Capybara, it's for full integration/feature tests. Instead you should build them using factory_girl like you are for user
factory :user do
# you current user factory code
# stays here
factory :user_with_filters do
transient do
filters_count 2
end
after(:create) do |user, proxy|
create_list(:filter, proxy.filters_count, user: user)
end
end
end
and then instead of let(:user) { FactoryGirl.create(:user) } do let(:user) { FactoryGirl.create(:user_with_filters) }
Pluck is a method restricted to ActiveRecord::Relation, so unless you also stub a method on fake_filters called pluck, just like you did on Filter
However, what I would do is just use .map(&:id) instead of .pluck(:id). The difference between map and pluck is that map is not efficient during querying since it will do a SELECT * FROM filters instead of SELECT id FROM filters in the case of pluck. Map also allows querying anything the object responds to, not only the active record attributes. However, here, it should be fine.

Rspec-rails 4 error: ActiveModel::ForbiddenAttributesError

I have an application running in rails 4.1 using mongoid as the orm. I created a model called User which has an attribute email. I am using RSpec for tests. I created the following spec
require 'spec_helper'
describe 'User' do
before(:each) do
#attr = {
user: {
email: "rahul#gmail.com"
}
}
end
it "should create a valid User instance" do
param = ActionController::Parameters.new(#attr)
param.require(:user).permit!
User.create!(param)
end
end
when I run the spec, I get the following error
Failure/Error: User.create!(param)
ActiveModel::ForbiddenAttributesError:
ActiveModel::ForbiddenAttributesError
I know this is related to strong parameters but couldn't figure out what I am doing wrong.
From the fine manual:
require(key)
[...] returns the parameter at the given key [...]
So saying param.require(:user) does nothing at all to param, it merely does an existence check and returns param[:user].
I think you want to say something more like this:
param = ActionController::Parameters.new(#attr)
User.create!(param.require(:user).permit!)
That usage would match the usual:
def some_controller_method
#user = User.create(user_param)
end
def user_param
param.require(:user).permit!
end
usage in controllers.

RSpec: how to test that parameters are correct in includes().where()

I am new in Rspec testing of Ruby on Rails and I have a question concerning controller tests.
Please, suggest me how to test this line:
#dreams = Dream.public_dreams.includes(:user).where("users.type_id = ?", 5)
In other words, I want to test if correct parameters were set in the controller. It should display all the dreams of a users with type_id equal to 5.
Can someone, please, help me out?
Since you've indicated that you "want to make sure...displayed dreams [are] only of users who have type_id equal to 5", this would seem to me more like a model spec than a controller spec, and I would probably refactor the code and spec it out to look something like this (assuming you still want to keep your rigid conditions):
First, refactor query into a scope in the model:
class DreamsController < ApplicationController
def your_action
#dreams = Dream.public_dreams_for_type_five_users
end
end
class Dream < ActiveRecord::Base
def self.public_dreams
# your code here to access public dreams
end
def self.public_dreams_for_type_five_users
public_dreams.includes(:user).where("users.type_id = ?", 5)
end
end
Next, test the scope in a model spec against some entries in the database that will pass and fail your expectations (the following spec uses FactoryGirl syntax, but you can substitute it out for whatever fixture-substitute library you like):
require 'spec_helper'
describe Dream do
describe ".public_dreams_for_type_five_users" do
let(:type_five_user_public_dreams) { Dream.public_dreams_for_type_five_users }
context "for users where type_id is 5" do
let!(:type_five_dream) { create(:dream, user: create(:user, type_id: 5)) }
it "includes the user's public dreams" do
expect(type_five_user_public_dreams).to include(type_five_dream)
end
end
context "for users where type_id is not 5" do
let!(:type_six_dream) { create(:dream, user: create(:user, type_id: 6)) }
it "does not include the user's public dreams" do
expect(type_five_user_public_dreams).to_not include(type_six_dream)
end
end
end
end
If you wanted, you could then go and further generalise the class method to be something like Dream.public_dreams_for_users_of_type(id) and change the specs accordingly.
There are several answers to that:
You could test the query itself:I would put such a query in a method or scope of your Dream model.Then go and test the query in a model spec.
You could test the assignment:On the other hand you can test the correct assignment in a controller spec with assigns[:dreams]
#dreams.select { |dream| dream.user.type_id = 5 }.should eq(#dreams) ?

Rails Custom Validators: Testing options

I'm trying to write up a rails gem that involves (amongst other things) some custom model validators...and I'm wondering how to test validation options.
To give an example, I'd like to write an rspec test for which a blank field returns valid if the allow_nil option is true, and invalid otherwise. The code works fine, but I can't think of an elegant way to test it. The code itself:
Module ActiveModel
module Validations
module ThirstyVals
class ValidatePrime < EachValidator
# Validate prime numbers
def validate_each(record, attr_name, value)
return if options[:allow_nil] && value.strip.length == 0
# Other validation code here
# ...
end
end
end
end
end
I'm currently testing through a dummy project, which is fine, but the only way I can think of to test the :allow_nil option is to write up a new attribute with :allow_nil set, and verify its functionality...which seems both excessive and pretty inelegant. There must be a more graceful way - any ideas appreciated. (Other tests below for posterity)
# ...
before(:each) do
#entry = Entry.new
end
describe "it should accept valid prime numbers" do
['7', '13', '29'].each do |n|
#entry.ticket = n
#entry.valid?('ticket').should be_true
end
end
describe "it should reject non-prime numbers" do
['4', '16', '33'].each do |n|
#entry.ticket = n
#entry.valid?('ticket').should be_false
end
end
have you considered testing the validator in isolation like so:
in validate_prime_spec.rb
require path_to_validator_file
describe ActiveModel::Validations::ThirstyVals::ValidatePrime do
context :validate_each do
it 'should do some stuff' do
subject.validate_each(record, attr_name, value).should #some expectation
end
end
end
then may I suggest that you need not test the allow_nil functionality of Rails validations due to the fact that it is already tested in Rails? (see: activemodel/test/cases/validations/inclusion_validation_test.rb line 44)

How to make a database field read-only in Rails?

I have a database table with a certain field which should be impossible to update once it has been inserted to the database. How do I tell my model that it shouldn't allow updating of a certain field?
You want to use attr_readonly:
Attributes listed as readonly will be used to create a new record but update operations will ignore these fields.
class Customer < ActiveRecord::Base
attr_readonly :your_field_name
end
Here's my related solution to a similar problem - we have fields that we want a user to be able to set themselves, we don't require them on creation of the record, but we do NOT want to them be changed once they are set.
validate :forbid_changing_some_field, on: :update
def forbid_changing_some_field
return unless some_field_changed?
return if some_field_was.nil?
self.some_field = some_field_was
errors.add(:some_field, 'can not be changed!')
end
The thing that surprised me, though, was that update_attribute still works, it bypasses the validations. Not a huge deal, since updates to the record are mass assigned in practice - but I called that out in the tests to make it clear. Here's some tests for it.
describe 'forbids changing some field once set' do
let(:initial_some_field) { 'initial some field value' }
it 'defaults as nil' do
expect(record.some_field).to be nil
end
it 'can be set' do
expect {
record.update_attribute(:some_field, initial_some_field)
}.to change {
record.some_field
}.from(nil).to(initial_some_field)
end
context 'once it is set' do
before do
record.update_attribute(:some_field, initial_some_field)
end
it 'makes the record invalid if changed' do
record.some_field = 'new value'
expect(record).not_to be_valid
end
it 'does not change in mass update' do
expect {
record.update_attributes(some_field: 'new value')
}.not_to change {
record.some_field
}.from(initial_some_field)
end
it 'DOES change in update_attribute!! (skips validations' do
expect {
record.update_attribute(:some_field, 'other new value')
}.to change {
record.some_field
}.from(initial_some_field).to('other new value')
end
end
end

Resources