Add new volunteer application form

This commit is contained in:
Petko Bordjukov 2015-10-21 23:13:39 +03:00
parent 1752a3bff9
commit c7c0b20139
17 changed files with 298 additions and 15 deletions

View File

@ -0,0 +1,41 @@
module Public
class VolunteersController < Public::ApplicationController
def new
@volunteer = current_conference.volunteers.build
end
def edit
@volunteer = current_conference.volunteers.find_by! unique_id: params[:id]
end
def create
@volunteer = current_conference.volunteers.build volunteer_params
if @volunteer.save
flash[:notice] = I18n.t('views.volunteers.successful_application')
redirect_to edit_volunteer_path(@volunteer.unique_id)
else
render :new, status: :unprocessable_entity
end
end
def update
@volunteer = current_conference.volunteers.find_by! unique_id: params[:id]
if @volunteer.update volunteer_params
flash[:notice] = I18n.t('views.volunteers.successful_application_edit')
redirect_to edit_volunteer_path(@volunteer.unique_id)
else
render :edit, status: :unprocessable_entity
end
end
private
def volunteer_params
params.require(:volunteer).permit(
:name, :picture, :email, :phone, :tshirt_size, :tshirt_cut,
:food_preferences, :previous_experience, :notes, :language,
volunteer_team_ids: []
)
end
end
end

View File

@ -0,0 +1,19 @@
# coding: utf-8
class VolunteerMailer < ActionMailer::Base
def team_notification(new_volunteer)
@volunteer = new_volunteer
mail(to: @volunteer.conference.email,
subject: "Нов доброволец #{@volunteer.name} <#{@volunteer.email}> за екипи #{@volunteer.volunteer_teams.map(&:name).join(', ')}")
end
def volunteer_notification(new_volunteer)
@volunteer = new_volunteer
I18n.locale = @volunteer.language
mail(to: @volunteer.email,
reply_to: @volunteer.conference.email,
from: 'no-reply@openfest.org',
subject: I18n.t('volunteer_mailer.success_notification.subject',
conference_name: @volunteer.conference.title))
end
end

View File

@ -13,6 +13,7 @@ class Conference < ActiveRecord::Base
has_many :event_types has_many :event_types
has_many :events has_many :events
has_many :volunteer_teams has_many :volunteer_teams
has_many :volunteers
has_one :call_for_participation, dependent: :destroy has_one :call_for_participation, dependent: :destroy
has_many :participants, class_name: 'User', through: :events has_many :participants, class_name: 'User', through: :events
has_many :slots, through: :halls has_many :slots, through: :halls

38
app/models/volunteer.rb Normal file
View File

@ -0,0 +1,38 @@
class Volunteer < ActiveRecord::Base
TSHIRT_SIZES = [:s, :m, :l, :xl, :xxl, :xxxl]
TSHIRT_CUTS = [:unisex, :female]
FOOD_PREFERENCES = [:none, :vegetarian, :vegan]
attachment :picture, type: :image
validates :name, :language, :tshirt_size, :tshirt_cut, :food_preferences, presence: true
validates :tshirt_size, inclusion: {in: TSHIRT_SIZES.map(&:to_s)}
validates :tshirt_cut, inclusion: {in: TSHIRT_CUTS.map(&:to_s)}
validates :food_preferences, inclusion: {in: FOOD_PREFERENCES.map(&:to_s)}
validates :email, format: {with: /\A[^@]+@[^@]+\z/}, presence: true
validates :phone, presence: true, format: {with: /\A[+\- \(\)0-9]+\z/}
validates :volunteer_teams, presence: true
phony_normalize :phone, default_country_code: 'BG'
belongs_to :conference
has_and_belongs_to_many :volunteer_teams
before_create :assign_unique_id
after_create :send_notification_to_organizers
after_create :send_notification_to_volunteer
private
def assign_unique_id
self.unique_id = Digest::SHA256.hexdigest(SecureRandom.uuid)
end
def send_notification_to_organizers
VolunteerMailer.team_notification(self).deliver_later
end
def send_notification_to_volunteer
VolunteerMailer.volunteer_notification(self).deliver_later
end
end

View File

@ -0,0 +1,22 @@
Здравейте,
<%= @volunteer.name %> <<%= @volunteer.email %>> изпрати кандидатура за доброволец.
Екипи: <%= @volunteer.volunteer_teams.map(&:name).join(', ') %>
Снимка: <%= attachment_url(@volunteer, :picture, host: "https://#{@volunteer.conference.host_name}/") %>
Език: <%= @volunteer.language %>
Телефон: <%= @volunteer.phone %>
Размер на тениска: <%= @volunteer.tshirt_size %>
Кройка на тениска: <%= @volunteer.tshirt_cut %>
Предпочитания за храна: <%= @volunteer.food_preferences %>
<% if @volunteer.previous_experience.present? -%>
Предходен опит:
<%= @volunteer.previous_experience %>
<% end -%>
<% if @volunteer.notes.present? -%>
Бележки:
<%= @volunteer.notes %>
<% end -%>

View File

@ -0,0 +1,7 @@
Здравейте,
Кандидатурата Ви беше получена.
Можете да я редактирате по всяко време от този адрес:
<%= edit_volunteer_url(@volunteer.unique_id, host: @volunteer.conference.host_name, protocol: 'https') %>

View File

@ -0,0 +1,7 @@
Hello,
Your application for volunteership was received.
You can edit it at any time on this address:
<%= edit_volunteer_url(@volunteer.unique_id, host: @volunteer.conference.host_name, protocol: 'https') %>

View File

@ -5,6 +5,9 @@ bg:
event: event:
create: "Изпрати предложение" create: "Изпрати предложение"
update: "Обнови предложението" update: "Обнови предложението"
volunteer:
create: "Изпрати кандидатура"
update: "Обнови кандидатурата"
actions: actions:
are_you_sure: "Сигурен ли си?" are_you_sure: "Сигурен ли си?"
create: create:
@ -61,6 +64,16 @@ bg:
picture: "Снимка" picture: "Снимка"
public_email: "Публичен e-mail" public_email: "Публичен e-mail"
twitter: Twitter акаунт twitter: Twitter акаунт
volunteer:
picture: Снимка
name: Име
email: E-mail
phone: Телефон
tshirt_size: Размер тениска
tshirt_cut: Кройка на тениска
food_preferences: Предпочитана храна
previous_experience: Предишен опит
notes: Бележки
track: track:
color: "Цвят" color: "Цвят"
description: "Описание" description: "Описание"
@ -96,6 +109,10 @@ bg:
invalid: "не е валиден e-mail адрес" invalid: "не е валиден e-mail адрес"
password_confirmation: password_confirmation:
confirmation: "не съответства на паролата" confirmation: "не съответства на паролата"
volunteer:
attributes:
picture:
invalid_content_type: "невалиден формат на снимката"
models: models:
conference: conference:
one: "конференция" one: "конференция"
@ -130,7 +147,7 @@ bg:
user: user:
one: "Потребител" one: "Потребител"
other: "Потребители" other: "Потребители"
volunteership: volunteer:
one: "доброволец" one: "доброволец"
other: "доброволци" other: "доброволци"
workshop: workshop:
@ -160,6 +177,9 @@ bg:
event_mailer: event_mailer:
acceptance_notification: acceptance_notification:
subject: "Предложението Ви за провеждане на %{submission_type} „%{title}“ на %{conference} е одобрено" subject: "Предложението Ви за провеждане на %{submission_type} „%{title}“ на %{conference} е одобрено"
volunteer_mailer:
success_notification:
subject: "Кандидатурата Ви за доброволец за %{conference_name} беше получена"
event_states: event_states:
approved: approved:
one: "Одобрено" one: "Одобрено"
@ -233,6 +253,22 @@ bg:
simple_form: simple_form:
error_notification: error_notification:
default_message: "Моля, разгледайте посочените грешки във формуляра:" default_message: "Моля, разгледайте посочените грешки във формуляра:"
options:
volunteer:
tshirt_size:
s: S
m: M
l: L
xl: XL
xxl: XXL
xxxl: XXXL
tshirt_cut:
unisex: Унисекс
female: Дамска
food_preferences:
none: Нищо специфично
vegetarian: Вегетарианец
vegan: Веган
hints: hints:
conference: conference:
description: "Описание на конференцията" description: "Описание на конференцията"
@ -262,6 +298,11 @@ bg:
picture: "Ваша снимка" picture: "Ваша снимка"
public_email: E-mail адрес, който ще бъде видим за посетителите public_email: E-mail адрес, който ще бъде видим за посетителите
twitter: "Потребителското Ви име в Twitter" twitter: "Потребителското Ви име в Twitter"
volunteer:
email: "Е-mail адресът Ви, който ще бъде видим само от организаторите"
phone: "Мобилният Ви телефон, който ще бъде видим само за организаторите"
picture: "Ваша снимка в jpeg, png или gif формат"
volunteer_teams: "Доброволческите екипи, от които искате да сте част. Подробни описания на екипите можете да намерите <a href=\"/volunteer_teams\" target=\"_blank\">тук</a>"
user: user:
email: e-mail адресът Ви. Ще бъде видим само от организаторите email: e-mail адресът Ви. Ще бъде видим само от организаторите
password: "Парола с дължина между 8 и 128 символа" password: "Парола с дължина между 8 и 128 символа"
@ -302,12 +343,15 @@ bg:
info: "Информация за потребител" info: "Информация за потребител"
welcome: welcome:
submit_event: "Предложи %{event_type}" submit_event: "Предложи %{event_type}"
volunteerships: volunteers:
apply: Кандидатствай new_volunteer_title: Кандидатствай за доброволец
edit_volunteer_title: "Кандидатура за доброволец на %{name}"
apply: Кандидатствай за доброволец
withdraw_application: Оттегли кандидатурата си withdraw_application: Оттегли кандидатурата си
you_successfully_applied_for: "Успешно изпратихте кандидатура за екип „%{team}“" successful_application: "Успешно изпратихте кандидатурата си"
successful_application_edit: "Успешно редактирахте кандидатурата си"
error_occurred_while_applying: "Възникна грешка и кандидатурата Ви не беше изпратена" error_occurred_while_applying: "Възникна грешка и кандидатурата Ви не беше изпратена"
you_successfully_retracted_your_application_for: "Успешно оттеглихте кандидатурата си за екип „%{team}“" you_successfully_retracted_your_application_for: "Успешно оттеглихте кандидатурата си“"
welcome: "Добре дошли, %{name}" welcome: "Добре дошли, %{name}"
what_we_ask: "Бихме искали да получим предложенията Ви за лекции и уъркшопи, принадлежащи към следните категории до 4 октомври 2015г.:" what_we_ask: "Бихме искали да получим предложенията Ви за лекции и уъркшопи, принадлежащи към следните категории до 4 октомври 2015г.:"
workshop_was_successfully_confirmed: "Уъркшопът беше потвърден успешно" workshop_was_successfully_confirmed: "Уъркшопът беше потвърден успешно"

View File

@ -9,6 +9,7 @@ Rails.application.routes.draw do
get :confirm get :confirm
end end
end end
resources :volunteers
resources :volunteerships, only: [:index, :destroy] resources :volunteerships, only: [:index, :destroy]
resources :volunteer_teams, only: [] do resources :volunteer_teams, only: [] do
resource :volunteership, only: :create resource :volunteership, only: :create

View File

@ -0,0 +1,20 @@
class CreateVolunteers < ActiveRecord::Migration
def change
create_table :volunteers do |t|
t.string :name
t.string :picture_id
t.string :email
t.string :unique_id
t.string :phone
t.string :tshirt_size
t.string :tshirt_cut
t.string :food_preferences
t.text :previous_experience
t.text :notes
t.timestamps null: false
end
add_index :volunteers, :unique_id, unique: true
end
end

View File

@ -0,0 +1,8 @@
class CreateJoinTableVolunteerVolunteerTeam < ActiveRecord::Migration
def change
create_join_table :volunteers, :volunteer_teams do |t|
t.index [:volunteer_id, :volunteer_team_id], name: 'volunteer_id_volunteer_team_id'
t.index [:volunteer_team_id, :volunteer_id], name: 'volunteer_team_id_volunteer_id'
end
end
end

View File

@ -0,0 +1,5 @@
class AddConferenceIdToVolunteers < ActiveRecord::Migration
def change
add_reference :volunteers, :conference, index: true, foreign_key: true
end
end

View File

@ -0,0 +1,5 @@
class AddLanguageToVolunteers < ActiveRecord::Migration
def change
add_column :volunteers, :language, :string
end
end

View File

@ -36,6 +36,26 @@ footer {
font-size: 1.7em; font-size: 1.7em;
} }
strong {
font-weight: 600;
}
span.radio {
label {
width: auto;
}
}
span.radio + span.radio {
label {
padding-left: 15px;
}
}
label.check_boxes {
height: 3em;
}
@media all and (max-width: 600px) { @media all and (max-width: 600px) {
.input label, .input input, .input span, .input .hint, .help-block, .input .error { .input label, .input input, .input span, .input .hint, .help-block, .input .error {
float: none; float: none;
@ -43,8 +63,22 @@ footer {
margin: 0; margin: 0;
} }
} span.radio, span.checkbox {
padding-top: 0.4em;
strong { label {
font-weight: 600; display: inline;
padding-left: 0;
input {
display: inline-block;
margin-right: 0.5em;
}
}
}
span.radio + span.radio {
label {
padding-left: 0;
}
}
} }

View File

@ -0,0 +1,21 @@
- form_url = @volunteer.new_record? ? volunteers_path : volunteer_path(@volunteer.unique_id)
= simple_form_for @volunteer, wrapper: :default, url: form_url do |f|
= f.error_notification
.form-inputs
.input
= attachment_image_tag(@volunteer, :picture, :fill, 150, 150) if @volunteer.picture.present?
= f.input :picture, as: :attachment, direct: true, wrapper: false
= f.input :name, autofocus: true
= f.input :email
= f.input :phone, input_html: {value: @volunteer.phone.try(:phony_formatted, format: :international)}
= f.association :volunteer_teams, as: :check_boxes, wrapper: :default
= f.input :language, as: :radio_buttons, collection: locale_collection, include_blank: false, wrapper: :default, checked: (@volunteer.language.presence || I18n.locale)
= f.input :tshirt_size, collection: Volunteer::TSHIRT_SIZES, as: :radio_buttons, wrapper: :default, checked: (@volunteer.tshirt_size.presence || :m)
= f.input :tshirt_cut, collection: Volunteer::TSHIRT_CUTS, as: :radio_buttons, wrapper: :default, checked: (@volunteer.tshirt_cut.presence || :unisex)
= f.input :food_preferences, collection: Volunteer::FOOD_PREFERENCES, as: :radio_buttons, wrapper: :default, checked: (@volunteer.food_preferences.presence || :none)
= f.input :previous_experience
= f.input :notes
.form-actions
= f.button :submit

View File

@ -0,0 +1,5 @@
- content_for(:title) { t 'views.volunteers.edit_volunteer_title', name: @volunteer.name }
h1 = t 'views.volunteers.edit_volunteer_title', name: @volunteer.name
= render 'form'

View File

@ -0,0 +1,5 @@
- content_for(:title) { t 'views.volunteers.new_volunteer_title' }
h1 = t 'views.volunteers.new_volunteer_title'
= render 'form'