Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ gem "rubocop-performance"
gem "rubocop-rails"
gem "rubocop-rails-omakase"

gem "minitest", "< 6"
gem "minitest-bisect"

gemspec
Expand Down
17 changes: 12 additions & 5 deletions lib/active_resource/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1477,6 +1477,12 @@ def dup
# is Json for the final object as it looked after the \save (which would include attributes like +created_at+
# that weren't part of the original submit).
#
# With <tt>save</tt> validations run by default. If any of them fail
# ActiveResource::ResourceInvalid gets raised, and nothing is POSTed to
# the remote system. To skip validations, pass <tt>validate: false</tt>. To
# validate withing a custom context, pass the <tt>:context</tt> option.
# See ActiveResource::Validations for more information.
#
# There's a series of callbacks associated with <tt>save</tt>. If any
# of the <tt>before_*</tt> callbacks throw +:abort+ the action is
# cancelled and <tt>save</tt> raises ActiveResource::ResourceInvalid.
Expand All @@ -1489,7 +1495,7 @@ def dup
# my_company.new? # => false
# my_company.size = 10
# my_company.save # sends PUT /companies/1 (update)
def save
def save(**options)
run_callbacks :save do
new? ? create : _update
end
Expand All @@ -1500,16 +1506,17 @@ def save
# If the resource is new, it is created via +POST+, otherwise the
# existing resource is updated via +PUT+.
#
# With <tt>save!</tt> validations always run. If any of them fail
# With <tt>save!</tt> validations run by default. If any of them fail
# ActiveResource::ResourceInvalid gets raised, and nothing is POSTed to
# the remote system.
# the remote system. To skip validations, pass <tt>validate: false</tt>. To
# validate withing a custom context, pass the <tt>:context</tt> option.
# See ActiveResource::Validations for more information.
#
# There's a series of callbacks associated with <tt>save!</tt>. If any
# of the <tt>before_*</tt> callbacks throw +:abort+ the action is
# cancelled and <tt>save!</tt> raises ActiveResource::ResourceInvalid.
def save!
save || raise(ResourceInvalid.new(self))
def save!(**options)
save(**options) || raise(ResourceInvalid.new(self))
end

##
Expand Down
2 changes: 1 addition & 1 deletion lib/active_resource/validations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ def save_with_validation(options = {})
# ones. Otherwise we get an endless loop and can never change the
# fields so as to make the resource valid.
@remote_errors = nil
if perform_validation && valid? || !perform_validation
if perform_validation && valid?(options[:context]) || !perform_validation
save_without_validation
true
else
Expand Down
26 changes: 26 additions & 0 deletions test/cases/validations_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,30 @@ def test_fails_save!
assert_raise(ActiveResource::ResourceInvalid) { p.save! }
end

def test_save_with_context
p = new_project(summary: nil)
assert_not p.save(context: :completed)
assert_equal [ "can't be blank" ], p.errors.messages_for(:summary)
end

def test_save_bang_with_context
p = new_project(summary: nil)
assert_raise(ActiveResource::ResourceInvalid) { p.save!(context: :completed) }
assert_equal [ "can't be blank" ], p.errors.messages_for(:summary)
end

def test_save_without_validation
p = new_project(name: nil)
assert_not p.save
assert p.save(validate: false)
end

def test_save_bang_without_validation
p = new_project(name: nil)
assert_raises(ActiveResource::ResourceInvalid) { p.save! }
assert p.save!(validate: false)
end

def test_validate_callback
# we have a callback ensuring the description is longer than three letters
p = new_project(description: "a")
Expand All @@ -56,6 +74,14 @@ def test_client_side_validation_maximum
assert_equal [ "is too long (maximum is 10 characters)" ], project.errors[:description]
end

def test_validation_context
project = new_project(summary: "")

assert_predicate project, :valid?
assert_not project.valid?(:completed)
assert_equal [ "can't be blank" ], project.errors.messages_for(:summary)
end

def test_invalid_method
p = new_project

Expand Down
1 change: 1 addition & 0 deletions test/fixtures/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class Project < ActiveResource::Base
validates :name, presence: true
validates :description, presence: false, length: { maximum: 10 }
validate :description_greater_than_three_letters
validates :summary, presence: { on: :completed }

# to test the validate *callback* works
def description_greater_than_three_letters
Expand Down