Explicando: na API REST você pode dar um POST à URL para chamar o método ‘create’. Porém não existe algo semelhante para chamar um ‘valid?’. Uma das maneiras de checar seu objeto ActiveResource antes de dar o POST é implementar validations na classe que estende o ActiveResource::Base.
O trecho que interessa é mais ou menos a partir da linha 219 deste arquivo na versão 2.0.2.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
class Person < ActiveResource::Base self.site = "https://www.localhost.com:3000/" protected def validate errors.add_on_empty %w( first_name last_name ) errors.add("phone_number", "has invalid format") unless phone_number =~ /[0-9]*/ end # is only run the first time a new object is saved def validate_on_create unless valid_member?(self) errors.add("membership_discount", "has expired") end end def validate_on_update errors.add_to_base("No changes have occurred") if unchanged_attributes? end end person = Person.new("first_name" => "Jim", "phone_number" => "I will not tell you.") person.save # => false (and doesn't do the save) person.errors.empty? # => false person.errors.count # => 2 person.errors.on "last_name" # => "can't be empty" person.attributes = { "last_name" => "Halpert", "phone_number" => "555-5555" } person.save # => true (and person is now saved to the remote service) |
Como podemos ver é uma simplicação do que teríamos num ActiveRecord::Base, mas serve. Porém veja como logo abaixo neste arquivo é implementado o método que deveria chamar as validações:
1 2 3 4 5 6 7 |
def save_with_validation save_without_validation true rescue ResourceInvalid => error errors.from_xml(error.response.body) false end |
Entenderam? Ele não chama a validação! Simplesmente chama novamente o método original (ver documentação sobre alias_method_chain para entender).
Não está claro porque isso está dessa maneira porque o módulo validation.rb parece ter tudo pronto para que as coisas funcionem conforme está na documentação. O ticket 10985 no Trac diz a mesma coisa mas ainda não foi solucionado.
Portanto, se você precisar dessa funcionalidade, não é difícil conseguir que funcione. Para tanto precisaremos de um pequeno monkey-patching. No arquivo config/environment.rb (ou algum outro dentro de config/initializers) coloque o seguinte:
1 |
require 'active_resource_validation' |
E crie o arquivo lib/active_resource_validation.rb com o seguinte:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
module ActiveResource::RealValidation def self.included(base) # :nodoc: base.class_eval { alias_method_chain :save, :real_validation } end def save_with_real_validation # :nodoc: validate if respond_to? :validate validate_on_create if new? && respond_to?(:validate_on_create) validate_on_update if !new? && respond_to?(:validate_on_update) valid? ? save_without_validation : false rescue ResourceInvalid => error errors.from_xml(error.response.body) false end end # solves https://dev.rubyonrails.org/ticket/10985 ActiveResource::Base.send :include, ActiveResource::RealValidation |
Pronto, agora as validations devem funcionar conforme está documentado. Eu chequei no trunk do Rails e até hoje isso ainda não está implementado.