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!