Różnice między .build, .create i .create! a kiedy należy ich używać?

167

Widziałem więc ludzi używających .build, .create i .create! w swoich kontrolerach ostatnio coraz częściej. Jaka jest różnica między zwykłym użyciem .new i przekazaniem obiektu param'd, a następnie .save? Czy są wady i zalety? Czy stosowanie innych metod przynosi korzyści?

Tim Knight
źródło

Odpowiedzi:

233

Jest kilka różnic, ale nie są one duże:

  1. .createjest równoważne z .newnastępującym po nim .save. Jest po prostu bardziej zwięzły.
  2. .create!jest równoważne .newnastępującemu po .save!(zgłasza błąd, jeśli zapisywanie się nie powiedzie). Jest też trochę krótszy
  3. Myślę, że .buildjest to głównie alias dla .new. To działa w jedną stronę w Rails 3 i inny sposób w Rails <3.x

Najważniejsze jest jednak to, że metody te można wywołać poprzez skojarzenie ( has_manyitp.), Aby automatycznie połączyć oba modele.

zenazn
źródło
1
Wybrałem tę odpowiedź jako najbardziej poprawną ze względu na wzmiankę o możliwości powiązania z nimi powiązanych modeli - to interesująca i ważna różnica, o której myślę, używając .new i .save. Co wymaga trochę dodatkowej pracy. Dzięki.
Tim Knight,
11
Drobne wyjaśnienie dotyczące 3 - build robi trochę więcej niż tylko nowy - ustawia również link asocjacyjny.
Two Bit Gangster
116
Budowa różni się od nowej. Ale różnica nie polega na tym, że ustawia łącze asocjacyjne (New robi to również dla nowej instancji). Różnica polega na tym, że Build zapełnia obiekt wywołujący nową instancją, ale New nie. Na przykład: Wall.posts.new wyświetla nowy post powiązany z Twoją tablicą, ale Wall.posts jest nadal pusty po tym wywołaniu. Wall.posts.build wyświetla nowy post powiązany z Twoją tablicą, a Twoje Wall.posts zawiera teraz jeden post.
Amin Ariana
3
Czy to nie jest teraz tylko alias bez specjalnej funkcjonalności?
Gabriele Cirulli
14
W Rails 4 właśnie sprawdziłem w konsoli. wall.posts.new i wall.posts.build wypełniają obiekt ściany dokładnie w ten sam sposób. Oznacza to, że po wall.posts.new wall.posts nie jest pusty, jak twierdzi Amin w komentarzu.
Bot
35

Chociaż prawdą jest, że createwywołuje, newa następnie saveistnieje duża różnica między dwiema alternatywami w ich wartościach zwracanych.

Savepowraca znakami truelub falsew zależności od tego, czy obiekt został pomyślnie zapisany w bazie danych, czy nie. Można to następnie wykorzystać do sterowania przepływem, jak w pierwszym przykładzie w powyższym pytaniu.

Createzwróci model niezależnie od tego, czy obiekt został zapisany, czy nie. Ma to konsekwencje dla powyższego kodu, ponieważ górna gałąź ifinstrukcji będzie zawsze wykonywana, nawet jeśli obiekt nie przejdzie walidacji i nie zostanie zapisany.

Jeśli używasz createz logiką rozgałęzień, jesteś narażony na ciche awarie, co nie ma miejsca, jeśli używasz new+ save.

create! nie cierpi z powodu tego samego problemu, który powoduje, i wyjątku, jeśli rekord jest nieprawidłowy.

createAlternatywą może być użyteczne w regulatory, których respond_withużywa się do API (JSON / XML) odpowiedzi. W takim przypadku istnienie błędów w obiekcie spowoduje zwrócenie błędów w odpowiedzi o statusie unprocessable_entity, czyli dokładnie takim, jakiego oczekujesz od API.

Zawsze używałbym opcji new+ savedla html, zwłaszcza jeśli polegasz na wartości zwracanej do kontroli przepływu.

nmott
źródło
6

#create to krótsza wersja nowego i zapisz. #Stwórz! zgłasza wyjątek, jeśli walidacja nie była pozytywna.

rkj
źródło
5

Poparłbym powyższe odpowiedzi. Poza createtym nie można falsepodać argumentu, z którym można się posłużyć save. Podanie falsejako argument spowoduje pominięcie wszystkich walidacji szyn

Vineeth Pradhan
źródło