Покрокова інструкція по додаванню багатьох зображень до моделі

Якщо вам потрібно додати зображення до існуючої моделі у власному проекті,почніть з кроку 2 і замість нашої моделі Gallery підставте свою модель.

1. Створення навчального проекту

1.1 Створіть новий проект(ми використовуємо базу даних Postgres) і перейдіть в директорію проекту

rails new multiple_images_uploader -d postgresql
cd multiple_images_uploader

1.2 Створіть базу даних

rails db:create

1.3 Згенеруйте скафолд Gallery і запустіть міграцію

rails g scaffold Gallery title:string  
rails db:migrate

2. Підключення джему CarrierWave

2.1 Додайте джем CarrierWave в Gemfile файл свого проекту

gem 'carrierwave', '~> 1.0'

виконайте команду:

bundle install

3. Згенеруйте завантажувач(ми назвали наш завантажувач Image):

rails generate uploader Image

ця команда створить файл: app/uploaders/image_uploader.rb

4. Додайте колонку images до таблиці galleries

згенеруйте міграцію:

rails g migration add_images_to_galleries images:json
rails db:migrate

5. Встановіть завантажувач

В модель Gallery додайте метод mount_uploaders, в якості аргументів передайте символ з назвою колонки, в яку зберігатимуться зображення і завантажувач, який ми згенерували в кроці 3

app/models/gallery.rb

class Gallery < ApplicationRecord
  mount_uploaders :images, ImageUploader
end

6. В контролері Galleries в метод gallery_params додайте параметр з масивом зображень:
app/controllers/galleries_controller.rb

def gallery_params
  params.require(:gallery).permit(:title, {images: []})
end

7. Додайте наступний блок до паршалу для створення галерії

app/views/galleries/_form.html.erb

<div class="field">
   <%= form.label :images, "Images:" %>
   <%= form.file_field :images, multiple: true %>  
</div>

8. У файл show.html.erb додайте наступний параграф

app/views/galleries/show.html.erb

<p>
  <% @gallery.images.each do |image| %>
    <%= image_tag image.url %>
  <% end %>
</p>

9. Задайте кореневий маршрут

config/routes.rb

Rails.application.routes.draw do
  resources :galleries
  root to: 'galleries#index'
end

10. Запустіть сервер

в терміналі,в корневій папці проекту введіть команду:

rails server

в браузері введіть:

localhost:3000

Тепер при створенні нової галереї у вас буде можливість додавати декілька зображень(використовуйте SHIFT+SELECT щоб вибрати декілька зображень).

Автори: Олег Павлюк та Марія Кулакова.

Логін через Facebook, Google та Email в Rails (частина 2)

Продовження. Першу частину дивіться за посиланням: http://rubyforce.io/rails-devise-part-1/

Ми одразу ж розділимо дані користувача та способи автентифікації. Для цього створимо нову модель Authentication:

rails g model authentication provider:string uid:string user_id:integer

app/models/authentication.rb

class Authentication < AplicationRecord
  belongs_to :user
end

Згенеруємо контролер:

rails g controller authentications

app/controllers/authentication_controller.rb

class AuthenticationsController < ApplicationController
  def destroy
    @authentication = current_user.authentications.find(params[:id])
    @authentication.destroy
    flash[:notice] = "Successfully destroyed authentication."
    redirect_to root_path
  end
end

Єдина дія яку ми будемо виконувати безпосередньо над автентифікацією – це видалення. Створення буде відбуватися у іншому контролері відповідальному за callback’и.

В модель User додаємо зв’язок з authentications. А також додаткові модуль omniauthable та провайдерів. Метод apply_omniauth будує відповідні authentications для користувача. А метод класу set_user повертає існуючого або створює нового користувача. Обидва методи ми використаємо у callbacks_controllers.rb.

app/models/user.rb

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  has_many :authentications, dependent: :destroy

  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable,
         :omniauthable, omniauth_providers: [:facebook, :google_oauth2]

  def apply_omniauth(omniauth)
    authentications.build(provider: omniauth['provider'], uid: omniauth['uid'])
  end

  def self.set_user(omniauth)
    User.find_by(email: omniauth.info.email) || User.new(email: omniauth.info.email, password: Devise.friendly_token[0,20]) 
  end
end

Створюємо таблицю authentications:


rake db:migrate

Наступний крок – створити аплікації на Facebook та Google

Для цього реєструємось на developers.facebook.com та console.developers.google.com. Кожна аплікація надає нам ID та SECRET. Також важливо вказати Valid OAuth redirect URIs – це адреса нашого сайту http://localhost:3000/.

Зауваження: якщо ви плануєте розгортати свою аплікацію локально (так як в даному прикладі) то деактивуйте Use Strict Mode for Redirect URIs для Facebook.

Додаємо ID та SECRET:

config/initializers/devise.rb


...
# Facebook
config.omniauth :facebook, ENV['FACEBOOK_ID'], ENV['FACEBOOK_SECRET']

# Google
config.omniauth :google_oauth2, ENV['GOOGLE_ID'], ENV['GOOGLE_SECRET']
...

Ключі зберігаємо за допомого dotenv:

.env


...
FACEBOOK_ID=ХХХХХХХХХХХХХХХХ
FACEBOOK_SECRET=ХХХХХХХХХХХХХХХХ
GOOGLE_ID=ХХХХХХХХХХХХХХХХ
GOOGLE_SECRET=ХХХХХХХХХХХХХХХХ
...

Тепер потрібно створити контролер, який буде обробляти callback’и після авторизації. Для кожного провайдера потрібен окремий метод. Важлива саме назва. А так як функціонал методів однаковий, то можна використати alias_method:

app/controllers/callbacks_controller.rb

class CallbacksController < Devise::OmniauthCallbacksController
  def all
    omniauth = request.env["omniauth.auth"]
    authentication = Authentication.find_by_provider_and_uid(omniauth['provider'], omniauth['uid'])

    if authentication
      flash[:notice] = "Signed in successfully."
      sign_in_and_redirect(:user, authentication.user)
    elsif current_user || User.exists?(email: omniauth.info.email)
      user = current_user || User.find_by_email(omniauth.info.email)
      user.authentications.create!(:provider => omniauth['provider'], :uid => omniauth['uid'])
      flash[:notice] = "Authentication successful."

      if current_user
        redirect_to root_path
      else
        sign_in_and_redirect(:user, user)
      end
    else
      user = User.set_user(omniauth)
      user.apply_omniauth(omniauth)

      if user.save
        flash[:notice] = "Signed in successfully."
        send_set_password_email(user)
        sign_in_and_redirect(:user, user)
      else
        cookies[:omniauth] = omniauth.except('extra')
        redirect_to new_user_registration_url
      end
    end
  end

  alias_method :facebook, :all
  alias_method :google_oauth2, :all

  private

  def send_set_password_email(user)
    user.send_reset_password_instructions
  end
end

Фактично, у цьому контролері міститься вся логіка нашої аплікації. Ми переверіяємо наявність автентифікацій та користувача і виконуємо відповідні дії по їх створенню та логінізації. Важливий момент – це надсилання листа новоствореному користувачу за допомогою send_set_password_email. В даному випадку ми використовуємо вже існуючий mailer Devise’у reset_password_instructions. Але можна також створити та налаштувати власний mailer.

І додаємо шляхи для даного контролера, а також для users та authentications:

config/routes.rb

Rails.application.routes.draw do
  root to: 'home#index'

  devise_for :users, controllers: { omniauth_callbacks: 'callbacks' }
  resources :users
  resources :authentications, only: [:destroy]
end

Налаштування для роботи mailer‘а:

config/environment/development.rb


...
config.action_mailer.perform_caching = false
config.action_mailer.perform_deliveries = true
config.action_mailer.raise_delivery_errors = true
config.action_mailer.default_options = { from: ENV['EMAIL_USERNME'] }
config.action_mailer.default_url_options = { host: "localhost:3000" }

config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
		address:              'smtp.gmail.com',
		port:                 587,
		domain:               'localhost',
		user_name:            ENV['EMAIL_USERNAME'],
		password:             ENV['EMAIL_PSWD'],
		authentication:       'plain',
		enable_starttls_auto: true  }
...

Тут доволі стандартні налаштування для Gmail. Знову ж таки ми використовуємо змінні оточення (ENV) для вразливих даних (адреса пошти та пароль).

.env


EMAIL_USERNAME=ХХХХХХХХХХХХХХХХ
EMAIL_PSWD=ХХХХХХХХХХХХХХХХ

На даний момент є одна проблема. Коли користувач перейде за посиланням в листі, то відбудеться редірект на головну сторінку. Це відбувається тому що користувач залогінений. Для того щоб пропустити перевірку, потрібно модифікувати passwords_controller.rb. Це один із контролерів Devise’у, в якому міститься відповідна логіка. Створюємо контролер:

app/controllers/passwords_controller.rb

class PasswordsController < Devise::PasswordsController
  skip_before_action :require_no_authentication, :only => [:edit, :update]

  def update
    super
    if resource.errors.empty?
      sign_out(resource_name)
      sign_in(resource_name, resource)
    end
  end
end

Тепер при реєстрації за допомогою аккаунту соціальних мереж, користувач отримає лист із можливістю встановити новий пароль, який можна буде використовувати для логіну.

P.S.

На головній сторінці відображається повідомлення про те, що користувач з певним email залогінився у певний спосіб:

app/views/home/index.html.erb


<p id="notice"><%= notice %></p>

<h1>Authentication with multiple social network accounts</h1>
<% if current_user %>
  <p>You are logged in as <mark><%= current_user.email %></mark> with <mark><%= @provider %></mark></p>
<% else %>
  <p>Please Log In</p>
<% end %>

У контролері визначена змінна @provider, яка може містити назву провайдера (facebook, google_oauth2) або email. Значення зберігається у cookies: app/controllers/home_controller.rb

class HomeController < ApplicationController
  def index
    @provider = cookies[:provider]
  end
end

Для того щоб мати коректне значення cookies[:provider] створюємо ініціалізатор, який буде спрацьовувати після логінізації та після logout’у користувача:

config/initializers/warden_hooks.rb

Warden::Manager.after_set_user except: :fetch do |user, auth, opts|
  if auth.request.env['omniauth.auth']
    auth.cookies[:provider] = auth.request.env['omniauth.auth'][:provider]
  else
    auth.cookies[:provider] = 'email'
  end
end

Warden::Manager.before_logout do |user,auth,opts|
  auth.cookies.delete :provider
end

Автор: Ілля Кузьма

Логін через Facebook, Google та Email в Rails (частина 1)

 

Велика кількість аплікацій потребує систему реєстрації та автентифікації користувачів. Це складне завдання. Так як йдеться про безпеку персональних даних. На щастя існує декілька хороших рішень для Rails фреймворку. Мабуть, найпоширенішим є Devise. Devise є досить простим у встановленні. Складність полягає у великій кількості можливих сценаріїв.

В залежності від потреб бізнесу можна організувати різні способи реєстрації. Якщо достаньо отримати пошту користувача, яка буде також виконувати роль логіну, і запитувати пару логін / пароль для входу, то стандартні налаштування Devise – це те що потрібно.

У цій статті ми розглянемо більш складний flow:

    1. Відвідувач має можливість обрати спосіб реєстрації: за допомогою аккаунтів facebook чи google, або через пошту.
    1. Після реєстрації через пошту користувач може під’єднати аккаунти соціальних мереж (facebook та/чи google)
    1. Після входу через один із аккаунтів соціальних мереж користувач отримує лист де має змогу перейти на сторінку встановлення паролю для входу.
    1. В подальшому користувач може від’єднати акаунти соціальних мереж та повністю видалити акаунт на сайті.

У статті ми крок за кроком пройдемо весь шлях реалізації даного завдання.

Посилання на репозиторій https://github.com/RubyForceTeam/authentication_solution_illia108.git

Створюємо нову rails аплікацію з базою даних PostgreSQL (у разі розгортання на heroku це полегшить роботу):

rails new auth --database=postgresql
cd auth

Додаємо необхідні бібліотеки:

Gemfile

gem 'devise'
gem 'omniauth-facebook'
gem 'omniauth-google-oauth2'
gem 'dotenv-rails', groups: [:development, :test]

Перші три gem’и потрібні безпосередньо для реєстрації та авторизації користувачів. Останній dotenv-rails – для збереження конфіденційної інформації. Ми повернемось до нього пізніше.

bundle

Створюємо базу даних:

rails db:create

Налаштовуємо Devise:

rails generate devise:install
rails generate devise User
rake db:migrate

В результаті отримуємо модель User, відповідну міграцію та шлях.

Devise потребує визначеної головної сторінки:

rails g controller home index

Згенерували новий контроллер із методом index. Та встановлюємо цей метод на root_path:

config/routes.rb

Rails.application.routes.draw do
  root to: 'home#index'
  devise_for :users
end

Для зручності додамо мінімальну навігацію:

app/views/layouts/application.html.erb

Auth
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
  

  
    <%= link_to 'Home', root_path %>
    <%= link_to 'Users', users_path %>
    <% if current_user %>
      <%= link_to('Logout', destroy_user_session_path, method: :delete) %>
    <% else %>
      <%= link_to('Login', new_user_session_path) %>
    <% end %>
    <%= yield %>
  

Стартуємо сервер та перевіряємо результат:

rails s

Першу частину завершено. У нас є реєстрація користувачів за допомогою логіну та паролю.

Продовження дивіться за посиланням: http://rubyforce.io/rails-devise-part-2/

Автор: Ілля Кузьма