Cześć

w dzisiejszym odcinku chciałbym pokazać wam jak wysyłać maile. W poprzednim filmie pokazałem wam jak przygotować formularz. Więc dzisiaj chciałbym pokazać wam jak rozszerzyć jego funkcjonalność

jeżeli nie oglądaliście poprzedniego filmu to oczywiście zachęcam, ale możecie sobie pobrać kod z tamtego odcinka z gita. W ten sposób będzie mieli ten sam kod który ja mam teraz.

https://github.com/rubypopolsku/formularze

git clone [git@github.com](mailto:git@github.com):rubypopolsku/formularze.git

Ruby on rails bardzo ułatwia nam tworzenie maili ponieważ posiada Action Mailer. A więc ładnie opakowana magie railsów do wysyłania maili

gdy mamy już nasz kod możemy użyć generatora

rails generate mailer ContactMailer

zajrzyjmy sobie do pliku app/mailers/application_mailer.rb

jest to domyślny plik wszystkich mail

class ApplicationMailer < ActionMailer::Base
  default from: "from@example.com"
  layout 'mailer'
end

mamy w nim domyślny email i layout

nie wszystkie maile musimy wysyłać z tego samego adresu więc można to ustawiać per mailer, ale przeważnie jak raz to tutaj ustawimy to tak to już sobie żyje

przejdźmy więc do naszego mailera

class ContactMailer < ApplicationMailer
end

domyślnie jest to pusta klasa, nie ma w nim nic

utwórzmy więc w nim nową metodę np contact_message

def contact_message
end

w ten sposób mamy nowe metodę która absolutnie nie wie co ma robić

def contact_message(email)
	mail(to: params[:email], subject: 'Wiadomość testowa')
end

teraz jeżeli gdziekolwiek w kodzie odpalimy

ContactMailer.with(email: "foo@bar.dev").contact_message.deliver_now

wyśle email na email który podamy jako parametr. TYu

tyle, że owszem email wyśle ale nie mamy jeszcze jego treści. Po za tym miał nam wysyłać zawartość formularza.

Przejdźmy na chwilę do naszego kontrolera. Jak widzicie wszystkie informacje jakich potrzebujemy zapisywane są w ContactMessage a mail powinien być wysyłany po zapisie

dodajmy więc odpowiedni kod

def create
    unless params[:contact_message][:terms] == "1"
      flash[:notice] = 'Musisz wyraźić zgodę na przetwarzanie danych'
    else
      @contact_message = ContactMessage.new(message_params)

      if @contact_message.save
				ContactMailer.contact_message(@contact_message).deliver_now
        flash[:notice] = 'Wiadomość zapisana'
      else
        flash[:notice] = 'Coś poszło nie tak'
      end
    end

    redirect_to new_contact_message_path
  end

po zapisaniu w bazie (tutaj już decyzja należy do was czy w ogóle jest sens taki formularz zapisywać w bazie) wysyła email

przejdźmy więc do naszego mailera który nie wie jeszcze nic o @contact_message

def contact_message(message)
	@message = message
	mail(to: @message.email, subject: @message.title)
end

by móc korzystać z danych zapisanych w modelu ContactMessage musimy dodać znak małpy przed zmienna message wtedy widok będzie miał do tego dostęp.

No właśnie. Mamy już logikę wysyłania maila, ale nie mamy maila który będzie wysyłany.

Nasz generator utworzył nam nowy katalog w widokach ale musimy utworzyć sam widok

contact_message.html.erb

<!DOCTYPE html>
<html>
  <head>
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
  </head>
  <body>
		<p><%= @message.name %> o emailu <%= @message.email %> wysłał Ci wiadomość</p>
    <p><b><%= @message.title %></b></p>
		<p><%= @message.body %></p>
  </body>
</html>

dobrą praktyką jest dodanie takiego samego widoku w wersji tekstowej, dla klientów którzy nie używają htmla w mailach

stwórzmy więc message.text.erb

<%= @message.name %> o emailu <%= @message.email %> wysłał Ci wiadomość
===============================================

<%= @message.title %>

<%= @message.body %>

konfiguracja maili

Teoretycznie to wszystko, gdyby nie jedno małe ale. Musimy jeszcze dodać jakiś serwer pocztowy który te maile będzie wysyłać

jeżeli używacie gmaila to w application.rb możecie dodać konfiguracje

config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  address:              'smtp.gmail.com',
  port:                 587,
  domain:               'example.com',
  user_name:            '<username>',
  password:             '<password>',
  authentication:       'plain',
  enable_starttls_auto: true
}

ALE!

taka konfiguracja będzie działać zarówno dla produkcji jak i naszego lokalnego środowiska a chyba nie chcemy wysłać maili podczas testów.

a sam gmail też nie jest najlepszym rozwiązaniem.

Przenieśmy więc ten konfig do naszego konfigu produkcyjnego

przenieśmy to do config/environments/production.rb

teraz dodajmy gem gem "letter_opener", :group => :development

i w config/environments/development.rb

ustawmy

config.action_mailer.delivery_method = :letter_opener
config.action_mailer.perform_deliveries = true

dzięki temu wszystkie maile będą uruchamiane u nas lokalnie

a maile z produkcji będą wysyłane przez konto gmaila, które jak wspomniałem nie jest dobrym pomysłem

jeżeli używacie heroku to możecie użyć np mailguna który do 400 maili dziennie jest za darmo

https://elements.heroku.com/addons/mailgun

sam konfig będzie wyglądał prawie tak samo

ActionMailer::Base.smtp_settings = {
  :port           => ENV['MAILGUN_SMTP_PORT'],
  :address        => ENV['MAILGUN_SMTP_SERVER'],
  :user_name      => ENV['MAILGUN_SMTP_LOGIN'],
  :password       => ENV['MAILGUN_SMTP_PASSWORD'],
  :domain         => 'yourapp.heroku.com',
  :authentication => :plain,
}
ActionMailer::Base.delivery_method = :smtp

a jak dodacie wtyczkę wszystkie envy ustawią wam się samodzielnie

Na dzisiaj to już tyle

Dziękuje za oglądanie. Miłego kodowania!

Kod aplikacji