Niezrozumiałe zachowanie klasy

Hej!
Staram się stworzyć klasę, która zajmować by się miała tworzeniem rekordu w bazie wraz ze “specyficzną” walidacją i paroma innymi rzeczami (część warstwy service w mojej aplikacji) i generalnie nie było by w tym niczego szczególnego, gdyby nie fakt, że kompletnie nie mogę zrozumieć jej zachowania. Kod jest następujący:

class PlacesService::InviteUser

  attr_reader :place
  attr_reader :user
  attr_reader :role
  attr_reader :place_user

  def initialize(place, params)
    @user  = User.find_by(email: params[:user][:email])
    @place = place
    @role  = params[:role] || 'employee'

    @place_user = @place.place_users.new(user: @user, role: @role)

    # If user has not been found, remove all other validation errors and
    # add just one with info about email not found
    unless @user.present?
      @place_user.errors.clear
      @place_user.errors.add(:base, 'No email found')
    end
  end

  def call
    @place_user.save! if valid?
  end

  def place_user
    @place_user
  end

  def valid?
    @place_user.valid?
  end

  def errors
    @place_user.errors
  end

end

Używam tego serwisu w kontrolerze w następujący sposób:

def create
    @service    = PlacesService::InviteUser.new(@place, place_user_params)
    @place_user = @service.place_user

    if @service.valid?
      @service.call
      render 'show'
    else
      render 'failure', status: :bad_request
    end
  end

Klasa ma za zadanie sprawdzić, czy w bazie istnieje user o podanym emailu i jeśli istnieje, to stworzyć rekord PlaceUser który wiąże Place z User. Jeśli nie, to na wyjściu mamy otrzymać jedynie jeden jedyny błąd walidacji (o nie istniejącym emailu) i pominąć wszystkie inne błędy. Czyli np. mogło by to wyglądać tak:

UserPlace.new(place_id: 1, role: 'owner').errors.full_messages
# => ["User can't be empty"]

PlacesService::InviteUser.new(@place, {user: {email: 'nieistniejacy@email.com'}})
# => ["No email found"]

Niestety, z jakiegoś powodu widok failure.jbuilder dla powyższego kontrollera nie wyświetla mi ‘No email found’ a wszystkie błędy walidacji. Czyli tak jak by nie wykonywał się blok unless w initialize(). Co ciekawe, dzieje się tak jedynie w wygenerowanym widoku; jeśli zdebuguje sobie zawartość @service.place_user.errors w dowolnym miejscu w kontrolerze, to komunikaty są poprawne (unless się wykonuje). Dołączam jeszcze kod widoku:

json.place_user do
  json.errors @place_user.errors
  json.full_error_messages @place_user.errors.full_messages
end

Sytuacja może brzmieć nieco skomplikowanie ale jest bardzo prosta. W razie czego śmiało pytajcie o szczegóły. Z góry dzięki za pomoc! :blush:

Jeśli PlaceUser dziedziczy z ActiveRecord::Base (lub ma odpowiednie mixiny ActiveModel), to cykl życia walidacji jest odpalany przez metodę valid? (m.in. czyszczenie obecnych błędów i uruchamianie walidatorów).
Dlatego ten błąd, który sobie dodałeś w initialize znika, a zamiast niego pojawiają się inne.

1 Like

No proszę! Nie wiedziałem o tym, wielkie dzięki za pomoc - teraz działa jak trzeba : )

1 Like