2

I am new to Rails and I am trying to look in my object to see if a value is true in order to validate all the other items in the object. I certainly have if the person is a user, validate the name and email within the app/model. What is the best way to write a spec for this?

class Members < ActiveRecord::Base
    validates_presence_of :email, if: :is_user?
    validates_presence_of :first_name, if: :is_user?
    validates_presence_of :last_name, if: :is_user?

    def is_user?
        :is_user
    end
end

2 Answers2

3

Do you have a field with the name "is_user" on the members table? It seems that method should return a boolean (true or false) while now it's returning a symbol which will always be evaluated to true, as an example, if you do

if :is_user
  puts "will always happen" # this will be printed
end

If there is the field on the database, then there's no need to create that method as rails generates methods with question mark for all boolean fields on the model database.

Now, to test that you can use a gem like shoulda_matchers or you can write your own tests like

describe "validations" do
  context "member is a user" do
    subject { Member.new(is_user: true) }

    it "validates presence of email" do
      subject.valid?
      expect(subject.errors["email"]).to include("can't be blank")
    end
  end

  context "member is not an user" do
    subject { Member.new(is_user: false) }

    it "doesn't require fields to have info" do
      subject.valid?
      expect(subject.errors["email"]).to_not include("can't be blank")
      expect(subject.errors["first_name"]).to_not include("can't be blank")
      expect(subject.errors["last_name"]).to_not include("can't be blank")
    end
  end
end
rafb3
  • 1,694
  • 12
  • 12
  • Yes, it is a boolean value. So I would need to do something different for the app model file? or what I have currently acceptable? – Katherine Bangert Dec 09 '14 at 16:46
  • if it is a boolean value that you have on the `is_user` field in the db, then remove that method, otherwise it will always be true and those validations will always be executed. If that's what you want, then you can remove the method and the `if: ...` part on the validation declaration – rafb3 Dec 09 '14 at 17:35
  • How does it know if you aren't explicitly saying that value must be true for the other fields to have values? – Katherine Bangert Dec 09 '14 at 17:41
  • hey, so `validates_presence_of :email, if: :is_user?` says, "only validate if email was passed if the member is a user", but, the method you defined for `is_user?` returns a symbol, not the value of the field on your database, but a ruby object that will always be evaluated to true. That validation then, is going to be run every time, and independently of the value of the field `is_user` on the database, because it is counting on the result of the `is_user?` method you defined which is always the same value, the symbol which evaluates to true. – rafb3 Dec 09 '14 at 17:44
  • when I say "evaluates to true", I mean when used on an if condition as `if :any_symbol` it will always enter execute whatever is after that. Different from `nil` or `false` which when used in an if statement will never execute the conditional code. – rafb3 Dec 09 '14 at 17:46
  • I am getting an error on the " is not user" part. It is coming back false. Should I be testing for a false condition? – Katherine Bangert Dec 09 '14 at 18:02
  • inspect the errors on `subject.errors.messages`, it's a map of fields to arrays of error messages, there it should say which errors that instance have that make it not `valid?`. It might turn out you have more validations than the ones you presented here, and then you should check for whether the fields of your interest (`email`, `first_name`, `last_name`) are present on the errors. I am updating the response to give you an idea – rafb3 Dec 09 '14 at 18:22
3

You should use shouda matchers it would be sort and pretty:
Example taken from here Shoulda/RSpec matchers - conditional validation

context "if user" do
  before { subject.stub(:is_user?) { true } }
  it { should validate_presence_of(:name) }
  it { should validate_presence_of(:email) }
end

context "if not user" do
  before { subject.stub(:is_user?) { false } }
  it { should_not validate_presence_of(:name) }
  it { should validate_presence_of(:email) }
end
Sebastián Palma
  • 32,692
  • 6
  • 40
  • 59
Ashutosh Tiwari
  • 984
  • 6
  • 16