2014-10-24 10 views
5

Gdzie znajdują się podstawowe weryfikatory podczas pracy z obiektami Form i zwykłymi modelami Rails?Powielone sprawdzanie poprawności we wszystkich obiektach i modelach formularzy

Zgodnie z koncepcją oddzielania formularzy od warstwy trwałości w Railsach. Skonfigurowałem obiekt formularza Cage, który tworzy razem dwa obiekty ... powiedzmy Animal i Plant.

Poniższe przykłady obiektu formularza z http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/ lub https://github.com/solnic/virtus lub https://github.com/makandra/active_type, każdy z nich pokazują sam obiekt forma walidacji ... nie ma problemu ... część korzyści to możliwość sprawdzania obiektów w bardziej świadomy sposób kontekstowo.

Emisja:

class Animal < ActiveRecord::Base 

    validates :color, presence: true 
    validate :only_one_brown 

    private 

    def only_one_brown 
    if some_complex_thing 
     errors.add(:color, 'can not have more than one brown animal.') 
    end 
    end 
end 

class Plant < ActiveRecord::Base 
    validates :color, presence: true 
end 

class Cage 
    include Virtus.model # or ActiveType or whatever 
    include ActiveModel::Validations 

    attribute :bird_color, String 
    attribute :plant_color, String 

    validates :bird_color, presence: true 
    validates :plant_color, presence: true 

    def save 
    if valid? 
     animal.save! 
     plant.save! 
     true 
    else 
     false 
    end 
    end 

    def animal 
    @animal ||= Animal.new(color: bird_color) 
    end 

    def plant 
    @plant ||= Plant.new(color: plant_color) 
    end 
end 

Jak mogę potwierdzić "tylko jeden brązowy" zasadę zwierzęcia bez:

  1. Zbyt dużo powielania.
  2. dużo kodu, aby Cage nadal działać jak model AR

Jeśli nie powielać kod weryfikacyjny, gdy „tylko jeden brązowy” jest fałszywe, Cage nie ma dla niej błąd ... przebijemy, co wymaga od kontrolera złapania i złapania, co jest złe.

Jeśli wykonamy kopię kodu i jeśli istnieje kilka niestandardowych sprawdzeń, kopiujemy wiele kodu, a każdy inny obiekt formularza, który zajmuje się teraz zwierzętami, wymaga teraz podwójnego sprawdzania poprawności.

Jeśli przeniesiemy kod walidacyjny całkowicie z Animal do Cage, podobny problem: wszystkie obiekty, które wchodzą w interakcje z Animalem, muszą wiedzieć o zasadzie "tylko jeden brązowy", która polega jedynie na powielaniu walidatorów i otwieraniu łatwego sposobu zapomnij go gdzieś egzekwować.

Jeśli przeniesiemy tablicę błędów Animala do Cage'a, błąd Animal jest na :color, który jest niejednoznaczny dla Cage i pokazuje błąd na nazwie atrybutu, której nigdy nie wysłał klient. Jeśli chcesz odwzorować klucze błędów Animala na Cage'a Teraz musisz zachować mapę dla każdego obiektu Form, czujesz się śmierdząca.

Czy istnieją jakieś dobre wzorce lub sposoby radzenia sobie z tą sytuacją? Wydaje mi się, że jest to bardzo powszechne, gdy zaczynasz używać Form Objects, ale wszystkie przykłady są dość trywialne.

Z góry dziękuję!

+0

Czy kiedykolwiek znaleźć rozwiązanie? Używam sprawdzania poprawności jquery dla sprawdzania poprawności formularzy po stronie klienta, a następnie nadal sprawdzam tylko w modelu ActiveRecord, ale nadal chcę coś, jeśli nie pozwalają na js po stronie serwera. –

+0

http://stackoverflow.com/questions/39357913/how-to-handle-errors-for-session-if-session-is-not-an-active-record-model –

Odpowiedz

0

Na końcu punktu 3 na http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/ autor mówi: "Jako bonus, ponieważ logika walidacji jest często kontekstowa, może być zdefiniowana w miejscu, gdzie jest to ważne, zamiast konieczności ochrony walidacji w samym ActiveRecord. " Zgadzam się z Bryan Helmkamp, ​​umieszcza sprawdzanie poprawności tam, gdzie ma to znaczenie, nie trzeba go duplikować.

edycja:

Gdybym ci włożę walidacji tylko na modelu ActiveRecord. I będę aktualizować klasę Koszyk:

def save 
    if valid? 
    ActiveRecord::Base.transaction do 
     animal.save! 
     plant.save! 
    end 
    true 
    else 
    false 
    end 
rescue Exception => exception 
    raise if valid? 
    false 
end 

i dodam metodę, która zwraca błędy błędy klatki aktywa przypadkach zwierzęcia.

edytowane:

Myślę, że możesz przedefiniować ważne? metoda, a następnie błędy działają poprawnie:

class Cage 
    include ActiveModel::Model 

    def valid_with_mymodels? 
    valid_without_mymodels? && animal.valid? && plant.valid? 
    animal.errors.each do |attribute, error| 
     self.errors.add :"bird_#{attribute.to_s}", error 
    end 
    plant.errors.each do |attribute, error| 
     self.errors.add :"plant_#{attribute.to_s}", error 
    end 
    errors.empty? 
    end 
    alias_method_chain :valid?, :mymodels 

    ... 

end 

Tylko uważaj na nazwy swoich attrów.

Nie jestem pewien jak działa Virtus, z Railsami 4 możesz użyć ActiveModel :: Model, jeśli używasz szyn 3 Potrzebuję badań.

edycja:

Jeśli używasz Rails 3.2, nie można używać ActiveModel :: model, ale masz to samo z tym:

class Cage 
    extend ActiveModel::Naming 
    include ActiveModel::Conversion 
    include ActiveModel::Validations 

    ... 

end 
+0

Jest to swego rodzaju esencja pytania. .. ma znaczenie w obu miejscach. Ma to znaczenie dla samego modelu, ponieważ musi być egzekwowane wszędzie, gdzie model jest używany, ale ma również znaczenie dla obiektu formularza, który musi działać jak model AR dla kontrolerów/interfejsu użytkownika. Aby sprawdzenia poprawności w obu miejscach ... sprawdzania poprawności, które wymagają SQL wyszukiwania lub obliczenia w pewien sposób ... wydaje się nieprzyjemne, ale nieuniknione. –

+0

Dodano bardziej oczywisty przykład kodu, co próbuję powiedzieć. –

+0

Dzięki Alejandro, rzuciłem okiem na tę trasę, ale co, jeśli tylko kolor brązowy nie zostanie zatwierdzony ... 'animal.errors' zawiera teraz' {: color => 'tylko jeden brązowy dozwolony'} '. Jeśli zostanie to przekazane do Cage'a, ': color' nie jest atrybutem klatki, który to kolor ...': bird_color' ... więc obsługa staje się dość skomplikowana, ponieważ teraz musisz wiedzieć, że zwierzę zwraca ': color', gdy oznacza ': bird_color' dla Cage, itd., a formularz nie zobaczy błędu w': bird_color', chyba że mapujemy kolumny pomiędzy tymi dwoma. –

Powiązane problemy