Commit Graph

27 Commits

Author SHA1 Message Date
Elliot Winkler ca6a1ff9ee Improve messaging of .required and .optional
When the `required` and `optional` qualifiers on `belong_to` fail, the
message can be a little confusing. There are actually two ways to
satisfy both qualifiers. One way, of course, is to match the option on
the association with the qualifier itself, so if the association is
defined with `required: true`, that will match
`belong_to(...).required`, and if it's `required: false`, that will
match `belong_to(...).required(false)` (and similar for `optional`). The
second way, though, is to manually add a presence validation to the
association (this will obviously only match `required(true)`). We need
to update the failure message to reflect these cases.
2019-02-14 17:48:26 -07:00
Elliot Winkler cd96089a56 belongs_to: Change default req/opt to match global default
In Rails 5, belongs_to associations default to `required: true`. This is
configurable by setting
`ActiveRecord::Base.belongs_to_required_by_default` to true. In new
Rails 5 apps, this is set to true, because the Rails generator will add
an initializer with the following line in it:

  config.active_record.belongs_to_required_by_default = true

However, for Rails apps that have been upgraded from 4 to 5, this
initializer may not be present, and in that case, that setting will not
be set, and `belong_to` associations will not default to `required:
true`.

This means that under Rails 5, our `belong_to` matcher cannot always
default to applying the `required` qualifier; it must abide by the
`belongs_to_required_by_default` setting in doing so.
2018-01-29 00:03:01 -06:00
Elliot Winkler 3af3d9f7ab Add required/optional qual's to belongs_to/has_one
Rails 5 made two changes to `belongs_to` associations:

* `required` and `optional` were added as options (which add and remove
  a presence validation on the association, respectively)
* `required` was made the default

In addition, a `required` option was also added to `has_one`.

These new qualifiers allow us to test these options appropriately.

Credit: Shia <rise.shia@gmail.com>
2017-10-06 23:38:47 -05:00
Elliot Winkler 5e1e531b8b Rails 5: Fix failing association matcher tests 2017-09-17 17:01:50 -05:00
Gui Albuk a6d09aa5de Fix #tables deprecation in Rails 5.0 and keep compatibility with Rails 4.x 2017-09-17 17:01:50 -05:00
Jacob Morris af85ac1f0e Add support for hbtm :join_table option
Rails supports declaring a `has_and_belongs_to_many` relationship with a
custom `:join_table` option and some developers want to assert that the
correct value is being used. Add `AssocationMatcher#join_table` to allow
developers to test the following:

1) That the :join_table option is being used for the relationship
2) That the *correct value* is being used
3) That the custom join table exists in the database
2015-04-04 00:19:28 -06:00
Jacob Morris 26a35978f6 Rename AssociationMatcher#join_table
Free up the `join_table` name so that users can specify a `join_table`
option when testing their associations.
2015-04-03 23:33:19 -06:00
Elliot Winkler a4045a1f9b Remove Rails 3.x, Ruby 1.9.2, Ruby 1.9.3
Ruby 1.9.3 will be end-of-lifed on February 23, 2015. We might as well
remove support for it now.
2015-02-09 10:52:22 -07:00
Sean Devine 948757b3f8 Dependent qualifier now supports more values
* :destroy
* :delete
* :nullify
* :restrict
* :restrict_with_exception (Rails 4+)
* :restrict_with_error (Rails 4+)
* true
* false
2015-01-20 14:10:14 -07:00
Elliot Winkler b4bf814b3b Fix association matchers + namespaced class_name
Fix `class_name` qualifier for association matchers so that if the
model being referenced is namespaced, the matcher will correctly resolve
the class before checking it against the association's `class_name`.

Take these models for instance:

module Models
  class Friend < ActiveRecord::Base
  end

  class User < ActiveRecord::Base
    has_many :friends, class_name: 'Friend'
  end
end

Here, the `has_many` is referring to Models::Friend, not just Friend.
Previously in order to test the association, you had to write:

    describe Models::User do
      it { should have_many(:friends).class_name('Models::Friend') }
    end

Now, `have_many` will attempt to resolve the string given to
`class_name` within the context of the namespace first before treating
it as a reference to a global constant. This means you can now write
this:

    describe Models::User do
      it { should have_many(:friends).class_name('Friend') }
    end
2014-11-06 14:15:00 -07:00
Elliot Winkler 7ef3cb6c19 Fix deprecation warning on Rails 3.2 2014-11-05 09:54:12 -07:00
Matt Gibson 0dd79ced47 Make sure foreign keys can be specified as symbols for has_and_belongs_to_many associations. 2014-10-09 01:36:04 -06:00
Elliot Winkler 48f45e814a Join table check for habtm w/ custom foreign keys should still work
If the habtm association in question specifies a custom foreign_key or
association_foreign_key, when the habtm matcher checks that the join
table has the correct columns, it should use the specified column names
instead of the defaults.
2014-07-21 00:12:19 -06:00
Jacob Morris 0695c8647b Check correct columns are present in join table
The `have_and_belong_to_many` matcher could give a false positive if the
join table is present but does not contain the correct columns. Check to
see if the columns exist in the join table and provide a meaningful
failure message if one or more of the columns are not present.
2014-07-21 00:08:42 -06:00
Sergey Kuchmistov 0d84ded157 Delete method redefining for OptionVerifier 2014-06-27 14:41:54 -06:00
Sergey Kuchmistov 198570db2c Prefer protected over private attributes 2014-06-27 14:41:54 -06:00
Elliot Winkler c22d7c89e0 Extract examples in README to inline documentation 2014-06-20 16:41:27 -06:00
Elliot Winkler c590a60108 Fix `belong_to` used with polymorphic association
For a polymorphic belongs_to association, the association doesn't
actually point to a class, it points to a concept, so we can't check
that the model it points to exists.
2014-04-12 14:49:01 -06:00
Mauro George 714cf87d78 Add support to rails 4.1.0 2014-04-08 17:41:31 -03:00
PikachuEXE 31a0913d7f + Add inverse of matcher for active record association 2014-04-04 11:15:55 -06:00
Elliot Winkler aff7bd7e2a Make `order` option Rails 4.0.1-compatible
The way that we figure out whether the value which is passed to `order`
is the same as the `order` that the association was defined with is by
creating an ActiveRecord::Relation object from the given `order` and
comparing it with the Relation stored under the association.
Specifically, every time you call `order` on a Relation, it appends the
value you've given to an internal `order_values` array, so we actually
access this array and compare the two between the two Relation objects.

Currently we assume that this `order_values` array is an array of
strings, so it's very easy to compare. That was valid pre-Rails 4.0.1,
but it looks like as per [these][1] [commits][2], it's now possible for
`order_values` to be an array of Arel nodes. So, to make a proper
comparison, we have to convert any Arel nodes to strings by calling
 #to_sql on them.

[1]: https://github.com/rails/rails/commit/d345ed4
[2]: f83c9b10b4
2013-12-18 22:32:28 -07:00
Luciano Sousa 803c06b0b0 Association matchers now support :source option 2013-12-01 15:12:49 -05:00
Elliot Winkler c6e1f86fa6 Fix converting association options to a Relation
Under Rails 3 when using an association matcher in conjunction with a
submatcher such as #order, we have to take the options on the
association (:conditions, :order, etc.) and convert them to an
ActiveRecord::Relation object. This happens in ModelReflector.

Unfortunately, converting an :includes option was broken. This is in
part due to ModelReflector not having proper tests, but also, the method
that does the conversion to Relation is rather complex and could be
broken up so it can be tested better. In fact I noticed that there's a
lot of stuff in ModelReflector that does stuff around a Reflection
object, so it would be better to define a ModelReflection class that
simply decorates a Reflection. That's what I've done and also added
proper tests.
2013-11-01 09:41:32 -06:00
Elliot Winkler 2b68f3859b Use relations to define conditions and order on associations
In Rails 4, the following construct:

  has_many :children, conditions: { adopted: true }

changes to:

  has_many :children, lambda { where(adopted: true) }

As a result, the way we check the conditions attached to a has_many
changes too: instead of accessing `reflection.options`, we have to use
`reflection.scope` -- this which refers to the lambda above, so we have
to evaluate it and then grab the `where` from the Relation that the
lambda returns.
2013-08-16 16:17:22 -06:00
Elliot Winkler 55f45d9549 Refactor AssociationMatcher to use new OptionVerifier
When using an association matcher you may have qualifiers on that
matcher which let you make assertions on options passed to the
association method that you are testing. For instance, has_many has a
:dependent option and so in order to test this you say something like

    it { should have_many(:people).dependent(:destroy) }

In order to test such an option we have to compare the option you passed
with what the actual value of that option is. This is usually obtained
by looking at the reflection object of the association in question,
although it can be obtained by other means too.

Anyway, the code that does this comparison isn't terrible, but there are
two problems with it. First, it involves typecasting both expected and
actual values. For instance, this:

    has_many :people, dependent: :destroy
    it { should have_many(:people).dependent(:destroy) }

should be equivalent to:

    has_many :people, dependent: :destroy
    it { should have_many(:people).dependent('destroy') }

should be equivalent to:

    has_many :people, dependent: 'destroy'
    it { should have_many(:people).dependent(:destroy) }

Second, we are a little screwed if the method of obtaining the actual
value of the option changes depending on which Rails version you're
using.

So, OptionVerifier attempts to address both of these issues. It's a
little crazy, but it works.

I also moved some methods from AssociationMatcher to ModelReflector
where they really belong.
2013-08-16 16:00:17 -06:00
Fabio Rehm 3f7c440851 Add support for counter_cache option in belongs_to associations 2013-06-21 10:53:30 -04:00
Melissa Xie 964dcfe655 Extract submatchers from AssociationMatcher
Refactored AssociationMatcher so that `#order`, `#through`, and `#dependent`
would be their own submatchers. This reduces some of the clutter in the main class,
especially as we continue expanding it. In addition, a few related tests were
modified so that they would check failure messages also.
2013-06-14 13:44:37 -04:00