2016-09-21 57 views
13

Od pewnego czasu utknąłem w tym problemie i całkowicie się pomyliłem co do tego, w jaki sposób modele zagnieżdżone i sprawdzania poprawności działają razem.Szyny: Zapobieganie tworzeniu modelu nadrzędnego i wyświetlanie błędów sprawdzania poprawności modelu dziecka

W poniższym kodzie moim celem jest niepowodzenie tworzenia modelu macierzystego (Obraz lub wideo), jeśli weryfikacja modelu podrzędnego (zawartość) zakończy się niepowodzeniem. Obecnie model nadrzędny jest zapisywany, podczas gdy model podrzędny nie jest, a błędy sprawdzania poprawności są niewidoczne. Jeśli nie ma błędów sprawdzania poprawności, wszystko działa zgodnie z oczekiwaniami.

#Image.rb 
has_one  :content, 
as:   :contentable, 
inverse_of: :contentable, 
dependent: :destroy 

#Video.rb 
has_one  :content, 
as:   :contentable, 
inverse_of: :contentable, 
dependent: :destroy 

#Content.rb 
belongs_to :contentable, 
inverse_of: :content, 
polymorphic: true 

validate  :all_good? 

def all_good? 
    errors.add(:base, "Nope!") 
    return false 
end 

Wszelkie wskazówki lub spostrzeżenia są doceniane!

+0

której wersji szyn używasz? – dnsh

+0

@ Dinesh Rails 4.2.6 – geoboy

+0

Dlaczego tak to ustawiasz - "zalecane podejście" nie jest naprawdę wykonalne, chyba że przedstawisz cel końcowy - czym właściwie jest rozumowanie do oddzielania takich elementów - co robią modele/Schemat wygląda jak w aplikacji, które wymagają tego oddzielenia? – MageeWorld

Odpowiedz

0

Musisz zgłosić wyjątek do niestandardowego sprawdzania poprawności. zrobić coś

before_save :ensure_all_good 

def ensure_all_good 
try saving stuff to chile 
failed? raise nope 
end 
+0

Interesujący pomysł. Czy nie powinienem być w stanie zrobić tego tylko dzięki obiektom walidacji i błędów, tym bardziej konwencjonalnym szynom? – geoboy

+0

Nie zaimplementowałem logiki, aby zaktualizować dzieci w moim walidatorze. Ponieważ byłoby to mylące. Dlatego właśnie wolałbym zaktualizować używając before_save i poradzić sobie z tym. Zawsze można umieścić dwie prośby wewnątrz transakcji, które również nie zostaną zatwierdzone. –

+0

@geoboy Właśnie natknąłem się na podobny problem, błędy z modelu potomnego nie są przekazywane do modelu nadrzędnego. W twoim przypadku, ponieważ walidacja znajduje się w modelu zawartości. Modele nadrzędne wideo i obrazu nie będą mogły wyświetlać błędów z treści. Możesz rzucić okiem na poniższy link, sugerując, w jaki sposób można łączyć błędy z modeli potomnych z rodzicami. http://stackoverflow.com/questions/2680016/ruby-on-rails-how-to-get-error-messages -z-dziecka-zasoby-wyświetlane –

4

Rails ma specjalny walidacja nazywa validates_associated zapewniający, że wiąże się zapis (s) jest prawidłowy. Jeśli powiązany rekord jest nieważny, rekord nadrzędny również będzie nieważny, a jego błąd zostanie dodany do listy błędów.

W obu klasach graficzne i wideo dodać następujące:

validates_associated :content 

Teraz, jeśli stowarzyszenie content jest nieważny nie zostanie zapisany plik wideo lub obrazu.

video = Video.new 
video.content = Content.new 
video.save #=> false 
video.valid? #=> false 
video.errors #=> [:content => "is invalid"] 
+0

dzięki za zabranie czasu na odpowiedź. niestety to nie działa. nadal zapisuje rekord (jeśli wstawię 'validates_presence_of: content', wówczas powie" treść nie może być pusta "). czy powoduje to zagnieżdżanie? również z dokumentacji: "UWAGA: Ta walidacja nie zakończy się niepowodzeniem, jeśli powiązanie nie zostało przypisane. Jeśli chcesz upewnić się, że powiązanie jest zarówno obecne, jak i zagwarantowane, że jest ważne, musisz również użyć validates_presence_of" – geoboy

4

Krótka odpowiedź

Dodaj do obrazów i wideo modelu

accepts_nested_attributes_for :content

dowód

byłem całkiem pewien, że zna odpowiedź na to, ale nie był pewien, czy działa z polimorficznym asocjatem jony (których wcześniej nie używałem), więc przygotowałem mały test.

Utworzono modele w taki sam sposób, jak konfigurację użytkownika, ale z atrybutem nazwy i walidacją, której można użyć do przetestowania pod kątem niepowodzenia.

class Image < ActiveRecord::Base 
    has_one  :content, 
       as:   :contentable, 
       inverse_of: :contentable, 
       dependent: :destroy 

    validates_length_of :name, maximum: 10 
end 

class Content < ActiveRecord::Base 
    belongs_to :contentable, 
       inverse_of: :content, 
       polymorphic: true 

    validates_length_of :name, maximum: 10 
end 

Następny setup migracje jak tak:

class CreateImages < ActiveRecord::Migration 
    def change 
    create_table :images do |t| 
     t.string :name 

     t.timestamps null: false 
    end 
    end 
end 


class CreateContents < ActiveRecord::Migration 
    def change 
    create_table :contents do |t| 
     t.string :name 
     t.references :contentable, polymorphic: true, index: true 

     t.timestamps null: false 
    end 
    end 
end 

Następny napisać rspec przetestować, że rodzic nie jest zapisany, jeśli dziecko nie może być zbawiony i że błędy walidacji perculate górę.

it 'should not save image if content is invalid' do 
    image = Image.new() 
    image.name = 'this is ok' 
    expect(image).to be_valid 

    content = Content.new() 
    content.name = 'a string that should fail validation' 
    image.content = content 

    expect(image).to_not be_valid 
    image.save 

    expect(image).to_not be_persisted 
    expect(content).to_not be_persisted 

    expect(image.errors.count).to eq(1) 
    expect(image.content.errors[:name][0]).to include('is too long') 
    end 

Przeprowadzono test i na pewno nie.

Następnie dodać następujący wiersz do obrazu (i filmu)

accepts_nested_attributes_for :content 

Testy teraz zdać - to znaczy, jeśli dziecko nie walidacja rodzic też nie walidacji i nie uratuje.