rails/rails — pull request #17727 by lleger (2014-11-23 17:48:50+00:00)
Title: Add bang, boolean method to MessageVerifier

This commit adds a `#verify!` bang method and a `#valid_message?` convenience boolean method to `ActiveSupport::MessageVerifier`.

**Bang method**
Contrary to my initial expectation, `#verify` actually raises an error if the message decoding fails. The first commit changes the behavior of `#verify` to return false when an error occurs instead; it continues to return the message on success. The commit also adds `#verify!`, which somewhat expectedly raises an error if decoding fails; it continues to return the message on success.

In my mind, this keeps with the convention of `#save` vs `#save!` and `#find` vs `#find!`. I understand that this commit changes behavior of an existing API and, thus, is a breaking change.

*Example*

```ruby
@verifier = ActiveSupport::MessageVerifier.new("c0mplexs3cret")
@data = @verifier.generate("a very important message")
@verifier.verify(@data) # => "a very important message"
@verifier.verify!(@data) # => "a very important message"
@verifier.verify("foo") # => false
@verifier.verify("foo") # => ActiveSupport::MessageVerifier::InvalidSignature
```

**Boolean method**
Sometimes it may be beneficial to verify the format of the message without performing the decoding. The second commit adds a `#valid_message?` boolean method which performs this validation. It has the added benefit of cleaning up a conditional in the `#verify` method. I also took some liberty restructuring the tests in this commit.

*Example*

```ruby
@verifier = ActiveSupport::MessageVerifier.new("c0mplexs3cret")
@data = @verifier.generate("a very important message") # => "BAhJIh1hIHZlcnkgaW1wb3J0YW50IG1lc3NhZ2UGOgZFVA==--4cf27b268ccb74307099b03d2b023f68b9e9763c"
@data.valid_message?(@data) # => true
@data.valid_message?("foo") # => false
@data.valid_message?("foo--bar") # => false
first, second = @data.split("--")
@data.valid_message?("#{first.reverse}--#{second.reverse}") # => false
@data.valid_message?("#{first}--#{second.reverse}") # => false
@data.valid_message?("#{first.reverse}--#{second}") # => false
@data.valid_message?("#{second}--#{first}") # => false
@data.valid_message?("#{first}--#{first}") # => false
```