Commit 9ba3fb4e authored by Rafael Reggiani Manzo's avatar Rafael Reggiani Manzo

Merge branch 'create_profile' into 'master'

Create profile

This PR enables a User to create a Profile. It incorporates the design too.

In spite of having all the CRUD, the only feature meant to be used right now is the Profile creation. All other actions exist but will likely fail (they were given to us by the scaffold). That's the reason for the pending unit tests too.

We chose to only implement the creation action because it is a minimum requirement for sending contents.

This should probably be accepted AFTER !4

See merge request !6
parents 0013cdc5 2872dc6b
Pipeline #3596392 passed with stage
in 12 minutes and 59 seconds
......@@ -36,6 +36,9 @@ gem 'devise'
# Browser language detection
gem 'http_accept_language'
# Country lists and form helpers
gem 'carmen'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 3.0'
# Use ActiveModel has_secure_password
......
......@@ -54,6 +54,8 @@ GEM
rack (>= 1.0.0)
rack-test (>= 0.5.4)
xpath (~> 2.0)
carmen (1.0.2)
activesupport (>= 3.0.0)
cliver (0.3.2)
coffee-rails (4.1.1)
coffee-script (>= 2.2.0)
......@@ -267,6 +269,7 @@ PLATFORMS
DEPENDENCIES
byebug
carmen
coffee-rails (~> 4.1.0)
cucumber-rails
database_cleaner
......
......@@ -14,6 +14,5 @@
//= require jquery_ujs
//= require foundation
//= require turbolinks
//= require_tree .
$(function(){ $(document).foundation(); });
function responsible_fields(event){
var current_year = new Date().getFullYear();
if(current_year - $('#profile_year').val() < 18) {
$('#responsible_fields').css('display', 'block');
$("#user-responsible-name").prop('required', true);
$("#user-responsible-id-number").prop('required', true);
} else {
$('#responsible_fields').css('display', 'none');
$("#user-responsible-name").prop('required', false);
$("#user-responsible-id-number").prop('required', false);
}
}
$('#profile_year').on('change', responsible_fields);
function school_fields(event){
if($('input[name=student]').first().is(':checked')) {
$('#school_fields').css('display', 'block');
$("#profile_school_type").prop('required', true);
$("#user-school-name").prop('required', true);
} else {
$('#school_fields').css('display', 'none');
$("#profile_school_type").prop('required', false);
$("#user-school-name").prop('required', false);
}
}
$('input[name=student]').on('change', school_fields);
function state_select(event) {
$.get('/states',
{ country: $('select#profile_country :selected').text(), locale: $('#locale').val() },
function(data) { $('div#state_select').html(data); }
);
}
$(document).ready(state_select);
$('select#profile_country').on('change', state_select);
class ProfilesController < ApplicationController
before_action :set_profile, only: [:show, :edit, :update, :destroy]
before_action :set_carmen_locale, only: [:show, :edit, :new, :states]
before_action :authenticate_user!, except: [:states]
respond_to :html
# GET /profiles/1
def show
end
# GET /profiles/new
def new
@profile = Profile.new
end
# GET /profiles/1/edit
def edit
end
# POST /profiles
def create
@profile = Profile.new(profile_params)
@profile.user_id = current_user.id
respond_to do |format|
if @profile.save
format.html { redirect_to root_path, notice: I18n.t('successfully_created_profile') }
else
format.html { render :new }
end
end
end
# PATCH/PUT /profiles/1
def update
respond_to do |format|
if @profile.update(profile_params)
format.html { redirect_to @profile, notice: 'Profile was successfully updated.' }
else
format.html { render :edit }
end
end
end
# DELETE /profiles/1
def destroy
@profile.destroy
respond_to do |format|
format.html { redirect_to profiles_url, notice: 'Profile was successfully destroyed.' }
end
end
def states
states = Carmen::Country.named(states_params).subregions
render partial: 'profiles/states', locals: { states: states }
end
private
# Use callbacks to share common setup or constraints between actions.
def set_profile
@profile = Profile.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def profile_params
complete_params = params.require(:profile).permit(:first_name, :last_name, :gender, :state, :city, :country, :school, :responsible_document, :responsible_name, :receive_mass_email, :phone, :user_id, :address, :zip_code, :occupation, :school_type)
complete_params[:birthdate] = Date.new params[:profile][:year].to_i, params[:profile][:month].to_i, params[:profile][:day].to_i
complete_params
end
def set_carmen_locale
Carmen.i18n_backend.locale = I18n.locale.to_s.split('-').first
end
def states_params
params.require(:country)
end
end
module ProfileHelper
def country_select
options_for_select Carmen::Country.all.map(&:name)
end
def state_select(states)
options_for_select states.map(&:name)
end
def occupation_select
options_for_select(I18n.t('occupations').map do |key, occupation|
key.zero? ? [occupation, nil] : [occupation, occupation]
end)
end
def school_type_select
options_for_select(I18n.t('school_types').map do |key, school_type|
key.zero? ? [school_type, nil] : [school_type, school_type]
end)
end
end
class Profile < ApplicationRecord
belongs_to :user
validates :terms_of_service, acceptance: true
validates :first_name, :last_name, :country, :state, :city,
:zip_code, :birthdate, :gender, :occupation, presence: true
validates :responsible_name, :responsible_document, presence: true, if: :underaged?
def adult?
((Time.zone.today - birthdate) / 365).to_i >= 18
end
def underaged?
!adult?
end
end
......@@ -6,4 +6,6 @@ class User < ApplicationRecord
:confirmable, :lockable, :timeoutable
validates :email, confirmation: true
has_one :profile
end
......@@ -28,7 +28,7 @@
<%= link_to t("account.edit"), '#' %>
</li>
<li>
<%= link_to t('profile_links.new'), '#' %>
<%= link_to t('profile_links.new'), new_profile_path %>
</li>
<li>
<!-- TODO: this would be a route to my_contents_path(current_user) -->
......
<div class="form-section">
<%= form_for(profile, 'data-abide' => true, novalidate: true) do |f| %>
<% if profile.errors.any? %>
<div id="error_explanation", data-abide-error class="alert callout">
<h2><p><i class="fa fa-exclamation-circle"></i><%= pluralize(profile.errors.count, 'error') %> prohibited this profile from being saved:</p></h2>
<ul>
<% profile.errors.full_messages.each do |message| %>
<li><%= message %></li>
<% end %>
</ul>
</div>
<% end %>
<fieldset>
<div class="field-label-item">
<h3><%= t('complete_your_registration') %></h3>
</div>
</fieldset>
<fieldset>
<div class="field-label">
<label for="user-email"><%= t('email') %> *</label>
</div>
<div class="field-item">
<%= f.email_field :email, id: 'user-email', required: true, disabled: true, value: current_user.email %>
</div>
</fieldset>
<fieldset>
<div class="field-label">
<%= f.label "#{t('first_name')} *", for: 'user-first-name' %>
</div>
<div class="field-item">
<%= f.text_field :first_name, required: true, id: 'user-first-name' %>
</div>
</fieldset>
<fieldset>
<div class="field-label">
<%= f.label "#{t('last_name')} *", for: 'user-last-name' %>
</div>
<div class="field-item">
<%= f.text_field :last_name, required: true, id: 'user-last-name' %>
</div>
</fieldset>
<fieldset>
<div class="field-label">
<%= f.label "#{t('address')} *", for: 'user-address' %>
</div>
<div class="field-item">
<%= f.text_field :address, id: 'user-address' %>
</div>
</fieldset>
<fieldset>
<div class="field-label">
<%= f.label "#{t('country')} *", for: 'profile_country' %>
</div>
<div class="field-item">
<%= f.select :country, country_select %>
</div>
</fieldset>
<div id="state_select">
</div>
<fieldset>
<div class="field-label">
<%= f.label "#{t('city')} *", for: 'user-city' %>
</div>
<div class="field-item">
<%= f.text_field :city, required: true, id: 'user-city' %>
</div>
</fieldset>
<fieldset>
<div class="field-label">
<%= f.label "#{t('zip_code')} *", for: 'user-postal-code' %>
</div>
<div class="field-item">
<%= f.text_field :zip_code, required: true, id: 'user-postal-code', placeholder: '99999-999' %>
</div>
</fieldset>
<fieldset>
<div class="field-label">
<%= f.label "#{t('birthdate')} *", for: 'user-birthdate' %>
</div>
<div class="field-item">
<%= select_date Date.today, prefix: 'profile', use_month_numbers: true, use_two_digit_numbers: true, start_year: Date.today.year - 50, end_year: Date.today.year - 10, order: [:day, :month, :year] %>
</div>
</fieldset>
<div id='responsible_fields' style='display:none'>
<fieldset class="user-responsible">
<div class="field-label">
<%= f.label "#{t('responsible_name')} *", for: 'user-responsible-name' %>
</div>
<div class="field-item">
<%= f.text_field :responsible_name, id: 'user-responsible-name', 'aria-describedby' => 'passwordHelpText' %>
</div>
</fieldset>
<fieldset class="user-responsible">
<div class="field-label">
<%= f.label "#{t('responsible_document')} *", for: 'user-responsible-id-number' %>
</div>
<div class="field-item">
<%= f.text_field :responsible_document, id: 'user-responsible-id-number', 'aria-describedby' => 'passwordHelpText' %>
</div>
</fieldset>
</div>
<fieldset>
<div class="field-label">
<%= f.label "#{t('gender')} *" %>
</div>
<div class="field-item">
<%= f.radio_button :gender, t('female'), checked: true %>
<%= f.label t('female') %>
<%= f.radio_button :gender, t('male') %>
<%= f.label t('male') %>
</div>
</fieldset>
<fieldset>
<div class="field-label">
<%= f.label t('student') %>
</div>
<div class="field-item">
<%= radio_button_tag :student, t('affirmative') %>
<%= f.label t('affirmative') %>
<%= radio_button_tag :student, t('negative'), checked: true %>
<%= f.label t('negative') %>
</div>
</fieldset>
<div id="school_fields" style="display:none">
<fieldset class="user-school">
<div class="field-label">
<%= f.label "#{t('school_type')} *", for: 'user-school-type' %>
</div>
<div class="field-item">
<%= f.select :school_type, school_type_select, id: 'user-school-type' %>
</div>
</fieldset>
<fieldset class="user-school">
<div class="field-label">
<%= f.label I18n.t "#{t('school')} *", for: 'user-school-name' %>
</div>
<div class="field-item">
<%= f.text_field :school, id: 'user-school-name' %>
</div><br>
</fieldset>
</div>
<fieldset>
<div class="field-label">
<%= f.label "#{t('occupation')} *", for: 'profile_occupation' %>
</div>
<div class="field-item">
<%= f.select :occupation, occupation_select %>
</div>
</fieldset>
<fieldset>
<div class="field-label">
<%= f.label t('phone'), for: 'user-phone' %>
</div>
<div class="field-item">
<%= f.text_field :phone, id: 'user-phone', placeholder: '(11) 99999-9999' %>
</div>
</fieldset>
<fieldset>
<div class="field-label-item">
<%= f.check_box :receive_mass_email %>
<%= f.label t('receive_newsletter'), for: :receive_mass_email %>
</div>
</fieldset>
<fieldset>
<div class="field-label-item">
<%= f.check_box :terms_of_service, id: 'user-terms', required: true %>
<%= f.label t('terms_of_service'), for: :terms_of_service %>
</div>
<div class="field-label-item recaptcha">[inserir código reCAPTCHA]</div>
<div class="field-label-item">
<%= f.submit t('save'), class: 'button' %>
</div>
</fieldset>
<% end %>
<%= hidden_field_tag('locale', I18n.locale) %>
</div>
<% content_for :footer do %>
<%= javascript_include_tag 'profiles/responsible_fields.js' %>
<%= javascript_include_tag 'profiles/school_fields.js' %>
<%= javascript_include_tag 'profiles/state_select.js' %>
<% end %>
<fieldset>
<div class="field-label">
<%= label_tag 'profile_state', "#{t('state')} *" %>
</div>
<div class="field-item">
<%= select_tag :state, state_select(states), name: 'profile[state]' %>
<span class="form-error">
Campo obrigatório.
</span>
</div>
</fieldset>
<h1>Editing Profile</h1>
<%= render 'form', profile: @profile %>
<%= link_to 'Show', @profile %> |
<%= link_to 'Back', profiles_path %>
<main>
<%= render 'form', profile: @profile %>
</main>
<p id="notice"><%= notice %></p>
<p>
<strong>First name:</strong>
<%= @profile.first_name %>
</p>
<p>
<strong>Last name:</strong>
<%= @profile.last_name %>
</p>
<p>
<strong>Birthdate:</strong>
<%= @profile.birthdate %>
</p>
<p>
<strong>Gender:</strong>
<%= @profile.gender %>
</p>
<p>
<strong>State:</strong>
<%= @profile.state %>
</p>
<p>
<strong>City:</strong>
<%= @profile.city %>
</p>
<p>
<strong>Country:</strong>
<%= @profile.country %>
</p>
<p>
<strong>School:</strong>
<%= @profile.school %>
</p>
<p>
<strong>Responsible document:</strong>
<%= @profile.responsible_document %>
</p>
<p>
<strong>Responsible name:</strong>
<%= @profile.responsible_name %>
</p>
<p>
<strong>Receive mass email:</strong>
<%= @profile.receive_mass_email %>
</p>
<p>
<strong>Phone:</strong>
<%= @profile.phone %>
</p>
<p>
<strong>User:</strong>
<%= @profile.user_id %>
</p>
<p>
<strong>Address:</strong>
<%= @profile.address %>
</p>
<p>
<strong>Zip code:</strong>
<%= @profile.zip_code %>
</p>
<p>
<strong>Occupation:</strong>
<%= @profile.occupation %>
</p>
<p>
<strong>School type:</strong>
<%= @profile.school_type %>
</p>
<%= link_to 'Edit', edit_profile_path(@profile) %> |
<%= link_to 'Back', profiles_path %>
......@@ -9,3 +9,4 @@ Rails.application.config.assets.version = '1.0'
# Precompile additional assets.
# application.js, application.css, and all non-JS/CSS in app/assets folder are already added.
# Rails.application.config.assets.precompile += %w( search.js )
Rails.application.config.assets.precompile += %w( profiles/*.js )
en:
complete_your_registration: Complete your registration
profile: Profile
first_name: First Name
last_name: Last Name
address: Address
city: City
state: State
country: Country
zip_code: Zip Code
birthdate: Birthdate
student: Student?
gender: Gender
male: male
female: female
occupation: Profession
phone: Phone number
receive_newsletter: Do you wish to receive our newsletter?
terms_of_service: Do accept our Terms and Conditions?
save: Save
successfully_created_profile: Profile was successfully created
affirmative: 'Yes'
negative: 'No'
responsible_name: Responsible's name
responsible_document: Responsible's document
school_type: School type
school: School
school_types:
0: Select a school type
1: State School
2: Public School
3: Private School
4: College
occupations:
0: Select an occupation
1: Management / Consuling
2: Arts / Entertainment
3: Science
4: Communication / Marketing
5: Construction
6: Education
7: Engineering
8: Finance
9: NGOs / TSOs
10: Professor
11: Recreation / Tourism
12: Health / Social Assistance
13: Technology
14: Transport / Logistics
15: Others
pt-BR:
complete_your_registration: Complete seu cadastro
profile: Perfil
first_name: Nome
last_name: Sobrenome
address: Endereço
city: Cidade
state: Estado
country: País
zip_code: CEP
birthdate: Data de nascimento
student: Você é estudante?
gender: Gênero
male: Masculino
female: Feminino
occupation: Profissão
phone: Telefone
receive_newsletter: Quero receber novidades por e-mail
terms_of_service: Li e concordo com o Regulamento e Termos de Uso
save: Cadastrar
successfully_created_profile: Perfil criado com sucesso
affirmative: Sim
negative: Não
responsible_name: Nome do(a) responsável
responsible_document: Documento do(a) responsável
school_type: Tipo de escola
school: Escola
school_types:
0: Selecione o tipo de escola
1: Escola Pública Estadual
2: Escola Pública Municipal
3: Escola Particular
4: Faculdade
occupations:
0: Selecione sua profissão
1: Administração / Consultoria
2: Artes / Entretenimento
3: Ciência
4: Comunicação / Marketing
5: Construção
6: Educação
7: Engenharia
8: Finanças
9: ONGs / Terceiro Setor
10: Professor
11: Recreação / Turismo
12: Saúde / Assistência Social
13: Tecnologia
14: Transporte / Logística
15: Outras
# Adapted from github.com/rails/rails/blob/master/activemodel/lib/active_model/locale/en.yml
errors:
# The default format to use in full error messages.
format: "%{attribute}: %{message}"
# The values :model, :attribute and :value are always available for interpolation
# The value :count is available when applicable. Can be used for pluralization.
messages:
model_invalid: "Falha de validação: %{errors}"
invalid: "é inválido"
confirmation: "não combina com %{attribute}"
accepted: "devem ser aceitos"
empty: "não pode ser vazio"
blank: "não pode ficar em branco"