Commit Graph

32 Commits

Author SHA1 Message Date
Ryuta Kamizono
e919a00848 Should find last created record
Tables in tests are not always empty so `klass.first` does not always
find last created record.

Fixes #36479.
2019-06-15 08:19:31 +09:00
Alan Wu
15b11ce505 Document option forwarding in ActiveRecord::Base.attribute
This has been supported for a while but we didn't have documentation
for it.
2019-03-20 15:05:31 -04:00
Rafael Mendonça França
a0482d3911
Make a deep copy of the _default_attributes in column_defaults
When column_defaults is called it calls `value` on each instance of
Attribute inside the _default_attributes set. Since value is memoized in
the Attribute instance and that Attribute instance is shared across all
instances of a model the next call to the default value will be memozied
not running the proc defined by the user.

Fixes #33031.
2018-09-20 00:03:15 -04:00
Daniel Colson
94333a4c31 Use assert_predicate and assert_not_predicate 2018-01-25 23:32:59 -05:00
Daniel Colson
211adb47e7 Change refute to assert_not 2018-01-25 23:32:58 -05:00
Yasuo Honda
6c6c3fa166 Suppress warning: BigDecimal.new is deprecated in activerecord
`BigDecimal.new` has been deprecated in BigDecimal 1.3.3
 which will be a default for Ruby 2.5.

Refer 533737338d

```
$ cd rails/activerecord/
$ git grep -l BigDecimal.new | grep \.rb | xargs sed -i -e "s/BigDecimal.new/BigDecimal/g"
```

- Changes made only to Active Record. Will apply the same change to
other module once this commit is merged.

- The following deprecation has not been addressed because it has been
reported at `ActiveRecord::Result.new`. `ActiveRecord::Result.ancestors`
did not show `BigDecimal`.

* Not addressed

```ruby
/path/to/rails/activerecord/lib/active_record/connection_adapters/mysql/database_statements.rb:34:
warning: BigDecimal.new is deprecated
```

* database_statements.rb:34

```ruby
ActiveRecord::Result.new(result.fields, result.to_a) if result
```

* ActiveRecord::Result.ancestors

```ruby
[ActiveRecord::Result,
 Enumerable,
 ActiveSupport::ToJsonWithActiveSupportEncoder,
 Object,
 Metaclass::ObjectMethods,
 Mocha::ObjectMethods,
 PP::ObjectMixin,
 ActiveSupport::Dependencies::Loadable,
 ActiveSupport::Tryable,
 JSON::Ext::Generator::GeneratorMethods::Object,
 Kernel,
 BasicObject]
```

This commit has been tested with these Ruby and BigDecimal versions

- ruby 2.5 and bigdecimal 1.3.3

```
$ ruby -v
ruby 2.5.0dev (2017-12-14 trunk 61217) [x86_64-linux]
$ gem list |grep bigdecimal
bigdecimal (default: 1.3.3, default: 1.3.2)
```

- ruby 2.4 and bigdecimal 1.3.0

```
$ ruby -v
ruby 2.4.2p198 (2017-09-14 revision 59899) [x86_64-linux-gnu]
$ gem list |grep bigdecimal
bigdecimal (default: 1.3.0)
```

- ruby 2.3 and bigdecimal 1.2.8

```
$ ruby -v
ruby 2.3.5p376 (2017-09-14 revision 59905) [x86_64-linux]
$ gem list |grep -i bigdecimal
bigdecimal (1.2.8)
```

- ruby 2.2 and bigdecimal 1.2.6
```
$ ruby -v
ruby 2.2.8p477 (2017-09-14 revision 59906) [x86_64-linux]
$ gem list |grep bigdecimal
bigdecimal (1.2.6)
```
2017-12-13 21:29:06 +00:00
Ryuta Kamizono
58c1dda4a2 Merge pull request #26707 from jcoleman/add_attribute_names_cache_busting_spec
Add test validating that Model.attribute_names cache is busted
2017-09-18 14:04:47 +09:00
Kir Shatrov
831be98f9a Use frozen-string-literal in ActiveRecord 2017-07-19 22:27:07 +03:00
Matthew Draper
87b3e226d6 Revert "Merge pull request #29540 from kirs/rubocop-frozen-string"
This reverts commit 3420a14590c0e6915d8b6c242887f74adb4120f9, reversing
changes made to afb66a5a598ce4ac74ad84b125a5abf046dcf5aa.
2017-07-02 02:15:17 +09:30
Kir Shatrov
cfade1ec7e Enforce frozen string in Rubocop 2017-07-01 02:11:03 +03:00
Sean Griffin
1bdc395d95 Make the second argument to attribute optional
While working on updating Paper Trail for 5.1 compatibility, I noticed
that I was required to pass a second argument to `attribute`. I didn't
intend for this to be the case, as `attribute :foo` is totally
reasonable shorthand for "I want `attr_accessor :foo`, but also have it
work with things like `.attributes` and `ActiveRecord::Dirty`"
2016-11-30 12:47:31 -05:00
James Coleman
46d0bbdbde Add test validating that Model.attribute_names cache is busted 2016-10-04 15:22:27 -04:00
Michael Grosser
a9aed2ac94
improve error message when include assertions fail
assert [1, 3].includes?(2) fails with unhelpful "Asserting failed" message

assert_includes [1, 3], 2 fails with "Expected [1, 3] to include 2" which makes it easier to debug and more obvious what went wrong
2016-09-16 12:03:37 -07:00
Sean Griffin
8ab9daf280 Include user defined attributes in inspect
The fact that this only includes column names is an oversight.
2016-08-31 14:46:40 -04:00
Xavier Noria
9617db2078 applies new string literal convention in activerecord/test
The current code base is not uniform. After some discussion,
we have chosen to go with double quotes by default.
2016-08-06 18:26:53 +02:00
Sean Griffin
f0ddf87e4b Correct the behavior of virtual attributes on models loaded from the db
Previously we had primarily tested the behavior of these attributes by
calling `.new`, allowing this to slip through the cracks. There were a
few ways in which they were behaving incorrectly.

The biggest issue was that attempting to read the attribute would
through a `MissingAttribute` error. We've corrected this by returning
the default value when the attribute isn't backed by a database column.
This is super special cased, but I don't see a way to avoid this
conditional. I had considered handling this higher up in
`define_default_attribute`, but we don't have the relevant information
there as users can provide new defaults for database columns as well.

Once I corrected this, I had noticed that the attributes were always
being marked as changed. This is because the behavior of
`define_default_attribute` was treating them as assigned from
`Attribute::Null`.

Finally, with our new implementation, `LazyAttributeHash` could no
longer be marshalled, as it holds onto a proc. This has been corrected
as well. I've not handled YAML in that class, as we do additional work
higher up to avoid YAML dumping it at all.

Fixes #25787
Close #25841
2016-07-25 11:12:06 -04:00
Jeremy Daer
89e2f7e722
Support for unified Integer class in Ruby 2.4+
Ruby 2.4 unifies Fixnum and Bignum into Integer: https://bugs.ruby-lang.org/issues/12005

* Forward compat with new unified Integer class in Ruby 2.4+.
* Backward compat with separate Fixnum/Bignum in Ruby 2.2 & 2.3.
* Drops needless Fixnum distinction in docs, preferring Integer.
2016-05-18 21:58:51 -07:00
Matthew Erhard
556e530da4 Define ActiveRecord::Attribute::Null#type_cast
Using ActiveRecord::Base.attribute to declare an attribute with a default value on a model where the attribute is not backed by the database would raise a NotImplementedError when model.save is called.

The error originates from 59d252196b/activerecord/lib/active_record/attribute.rb (L84).
This is called from 59d252196b/activerecord/lib/active_record/attribute.rb (L46) on an ActiveRecord::Attribute::Null object.

This commit corrects the behavior by implementing ActiveRecord::Attribute::Null#type_cast.

With ActiveRecord::Attribute::Null#type_cast defined, ActiveRecord::Attribute::Null#value (59d252196b/activerecord/lib/active_record/attribute.rb (L173..L175)) can be replaced with its super method (59d252196b/activerecord/lib/active_record/attribute.rb (L36..L40)).

fixes #24979
2016-05-11 13:21:01 -04:00
Sean Griffin
ba06dab545 Memoize user provided defaults before type casting
When a proc is given as a default value, the form builder ends up
displaying `Proc#to_s` when the default is used. That's because we
didn't handle the proc until type casting. This issue technically can
occur any time that a proc is the value before type casting, but in
reality the only place that will occur is when a proc default is
provided through the attributes API, so the best place to handle this
edge case is there.

I've opted to memoize instead of just moving the `Proc#call` up, as this
made me realize that it could potentially interact very poorly with
dirty checking.

The code here is a little redundant, but I don't want to rely on how
`value_before_type_cast` is implemented in the super class, even if it's
just an `attr_reader`.

Fixes #24249

Close #24306
2016-03-24 14:58:23 -06:00
Sean Griffin
9deb6ababe Ensure #reset_column_information clears child classes as well
I've added a redundant test for this under the attributes API as well,
as that also causes this bug to manifest through public API (and
demonstrates that calling `reset_column_information` on the child
classes would be insufficient)

Since children of a class should always share a table with their parent,
just reloading the schema from the cache should be sufficient here.
`reload_schema_from_cache` should probably become public and
`# :nodoc:`, but I'd rather avoid the git churn here.

Fixes #22057
2015-11-07 08:20:34 -07:00
Yves Senn
48a183ecb9 use assert_not instead of refute as mentioned in our guides.
As described in the "Follow Coding Conventions" section in our
contribution guide (http://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions)
we favor `assert_not` over `refute`.

While we don't usually make stylistic changes on it's own I opted to do
it in this case. The reason being that test cases are usually copied as
a starting point for new tests. This results in a spread of `refute` in
files that have been using it already.
2015-08-13 09:20:39 +02:00
Sean Griffin
17b846004d Fix minor typo in test name 2015-07-20 09:22:30 -06:00
Sean Griffin
2f9d88954c Persist user provided default values, even if unchanged
This is a usability change to fix a quirk from our definition of partial
writes. By default, we only persist changed attributes. When creating a
new record, this is assumed that the default values came from the
database. However, if the user provided a default, it will not be
persisted, since we didn't see it as "changed". Since this is a very
specific case, I wanted to isolate it with the other quirks that come
from user provided default values. The number of edge cases which are
presenting themselves are starting to make me wonder if we should just
remove the ability to assign a default, in favor of overriding
`initialize`. For the time being, this is required for the attributes
API to not have confusing behavior.

We had to delete one test, since this actually changes the meaning of
`.changed?` on Active Record models. It now specifically means
`changed_from_database?`. While I think this will make the attributes
API more ergonomic to use, it is a subtle change in definition (though
not a backwards incompatible one). We should probably figure out the
right place to document this. (Feel free to open a PR doing that if
you're reading this).

/cc @rafaelfranca @kirs @senny

This is an alternate implementation of #19921.

Close #19921.

[Sean Griffin & Kir Shatrov]
2015-05-28 16:40:26 -06:00
Sean Griffin
a6e3cdae0c Allow proc defaults with the Attributes API
This is a variant implementation of the changes proposed in #19914.
Unlike that PR, the change in behavior is isolated in its own class.
This is to prevent wonky behavior if a Proc is assigned outside of the
default, and it is a natural place to place the behavior required by #19921
as well.

Close #19914.

[Sean Griffin & Kir Shatrov]
2015-05-28 16:26:49 -06:00
Robin Dupret
95c2fc9679 Follow-up to #10776
The name `ActiveModel::AttributeAssignment::UnknownAttributeError` is
too implementation specific so let's move the constant directly under
the ActiveModel namespace.

Also since this constant used to be under the ActiveRecord namespace, to
make the upgrade path easier, let's avoid raising the former constant
when we deal with this error on the Active Record side.
2015-02-26 15:40:03 +01:00
Sean Griffin
9ca6948f72 type_cast_from_user -> cast 2015-02-17 13:39:42 -07:00
Sean Griffin
4a3cb840b0 Type#type_cast_from_database -> Type#deserialize 2015-02-17 13:28:48 -07:00
Sean Griffin
101c19f55f Allow a symbol to be passed to attribute, in place of a type object
The same is not true of `define_attribute`, which is meant to be the low
level no-magic API that sits underneath. The differences between the two
APIs are:

- `attribute`
  - Lazy (the attribute will be defined after the schema has loaded)
  - Allows either a type object or a symbol
- `define_attribute`
  - Runs immediately (might get trampled by schema loading)
  - Requires a type object

This was the last blocker in terms of public interface requirements
originally discussed for this feature back in May. All the
implementation blockers have been cleared, so this feature is probably
ready for release (pending one more look-over by me).
2015-02-06 11:51:13 -07:00
Sean Griffin
70ac072976 Attribute assignment and type casting has nothing to do with columns
It's finally finished!!!!!!! The reason the Attributes API was kept
private in 4.2 was due to some publicly visible implementation details.
It was previously implemented by overloading `columns` and
`columns_hash`, to make them return column objects which were modified
with the attribute information.

This meant that those methods LIED! We didn't change the database
schema. We changed the attribute information on the class. That is
wrong! It should be the other way around, where schema loading just
calls the attributes API for you. And now it does!

Yes, this means that there is nothing that happens in automatic schema
loading that you couldn't manually do yourself. (There's still some
funky cases where we hit the connection adapter that I need to handle,
before we can turn off automatic schema detection entirely.)

There were a few weird test failures caused by this that had to be
fixed. The main source came from the fact that the attribute methods are
now defined in terms of `attribute_names`, which has a clause like
`return [] unless table_exists?`. I don't *think* this is an issue,
since the only place this caused failures were in a fake adapter which
didn't override `table_exists?`.

Additionally, there were a few cases where tests were failing because a
migration was run, but the model was not reloaded. I'm not sure why
these started failing from this change, I might need to clear an
additional cache in `reload_schema_from_cache`. Again, since this is not
normal usage, and it's expected that `reset_column_information` will be
called after the table is modified, I don't think it's a problem.

Still, test failures that were unrelated to the change are worrying, and
I need to dig into them further.

Finally, I spent a lot of time debugging issues with the mutex used in
`define_attribute_methods`. I think we can just remove that method
entirely, and define the attribute methods *manually* in the call to
`define_attribute`, which would simplify the code *tremendously*.

Ok. now to make this damn thing public, and work on moving it up to
Active Model.
2015-01-31 19:42:38 -07:00
Bogdan Gusiev
2606fb3397 Extracted ActiveRecord::AttributeAssignment to ActiveModel::AttributesAssignment
Allows to use it for any object as an includable module.
2015-01-23 23:43:22 +02:00
Sean Griffin
4010a9ddc6 Don't modify the columns hash to set defaults from the attributes API
Nothing is directly using the columns for the default values anymore.
This step helps us get closer not not mutating the columns hash.
2014-10-31 16:06:14 -06:00
Sean Griffin
3fab9d8821 Rename property to attribute
For consistency with https://github.com/rails/rails/pull/15557
2014-06-07 07:20:25 -06:00