diff --git a/app/assets/javascripts/editor.js b/app/assets/javascripts/editor.js index 9e7aca9..98bd662 100644 --- a/app/assets/javascripts/editor.js +++ b/app/assets/javascripts/editor.js @@ -76,4 +76,25 @@ _input.addEventListener('change', function(event) { setRequired(); }); }); }); + + Array.prototype.forEach.call(document.querySelectorAll('[data-toggles]'), function(checkbox) { + var toggles = document.getElementById(checkbox.dataset.toggles); + toggles.classList.add('toggleable'); + var form = checkbox.parentNode; + while (form && form.nodeName != 'FORM') { + form = form.parentNode; + } + var toggle = function() { + toggles.classList[checkbox.checked ? 'add' : 'remove']('open'); + if (form) { + if (checkbox.checked) { + form.removeAttribute('novalidate'); + } else { + form.setAttribute('novalidate', 'novalidate'); + } + } + }; + toggle(); + checkbox.addEventListener('change', function(event) { toggle(); }); + }); })(); diff --git a/app/assets/stylesheets/_application.scss b/app/assets/stylesheets/_application.scss index 82fbcc9..323547f 100644 --- a/app/assets/stylesheets/_application.scss +++ b/app/assets/stylesheets/_application.scss @@ -239,7 +239,7 @@ textarea, .textarea { } input { - &[type="text"], &[type="password"], &[type="telephone"], &[type="search"], &[type="email"], &[type="url"] { + &[type="text"], &[type="password"], &[type="tel"], &[type="search"], &[type="email"], &[type="url"], &[type="number"] { display: block; font-size: 1.25em; outline: 0; @@ -249,10 +249,15 @@ input { padding: 0.25em 0.5em; border-bottom: 0.15em solid transparent; } + + &[type="number"], &[type="tel"] { + @include font-family(secondary); + } } .number-field, .email-field, +.telephone-field, .text-field { position: relative; margin-bottom: 2em; @@ -321,6 +326,10 @@ input { } } +.telephone-field { + max-width: 15em; +} + @include keyframes(bend) { to { @include _(transform, skewX(-5deg)); @@ -530,6 +539,10 @@ input { font-size: 0.75em; } +.check-box-field.inline { + display: inline-block; +} + .radio-button-field { label { width: 7em; @@ -582,11 +595,11 @@ form { } &.mini-flex-form { - display: flex; - align-items: flex-start; + @include _-(display, flex); + @include _(align-items, flex-start); .input-field { - flex: 1; + @include _(flex, 1); } button, .button { @@ -597,8 +610,27 @@ form { } fieldset { + margin: 0; padding: 0; border: 0; + + &.centered { + margin-top: 3em; + text-align: center; + } +} + +.fieldgroup { + @include _-(display, flex); + @include _-(display, inline-flex); + @include _(align-items, flex-end); + @include _(flex-wrap, wrap); + margin: 0 0 3em 1em; + + > .input-field { + margin-right: 1em; + @include _(flex, 1); + } } .view-object { @@ -645,9 +677,9 @@ fieldset { } &.next-prev { - display: flex; - flex-wrap: wrap; - flex-direction: row-reverse; + @include _-(display, flex); + @include _(flex-wrap, wrap); + @include _(flex-direction, row-reverse); margin: 0; button, .button { @@ -893,6 +925,7 @@ ul.warnings li, a { color: inherit; + position: static; @include before { content: ''; @@ -1152,15 +1185,15 @@ $header-tilt: 8deg; padding: 1em; footer { - display: flex; - flex-flow: row wrap; + @include _-(display, flex); + @include _(flex-flow, row wrap); font-size: 4.1vw; } .github, ul.locales { - flex: 1; - flex-basis: 50%; + @include _(flex, 1); + @include _(flex-basis, 50%); } .copy { @@ -1174,7 +1207,7 @@ $header-tilt: 8deg; } .facebook { - flex: none; + @include _(flex, none); margin: 0.5em; a { @@ -1255,16 +1288,17 @@ input[type="submit"]:focus { } .check-box-field input:focus + label, -.radio-button-field input:focus + label { - @include before { - background-color: $colour-2; - @include _(animation, colour-out ease-in-out 500ms infinite alternate both); - } +.radio-button-field input:focus + label, +.select-field select:focus { + outline: 0.25rem solid $colour-2; + outline-offset: 0.2rem; + z-index: 1; } body { input:focus, textarea:focus, + select:focus, .textarea { @include _(animation, none); } @@ -2177,15 +2211,31 @@ html[data-lingua-franca-example="html"] { select { display: block; - width: 100%; - height: 2.1em; + height: 1.75em; font-family: inherit; font-size: 1.5em; - padding: 0.25em; + padding: 0 0.5em; + border: 0.1em solid #333; + cursor: pointer; @include default-box-shadow(top, 1.5, false); } } +.toggleable { + @include _(transition, 'transform 250ms ease-in-out, max-height 250ms ease-in-out, visibility 0s linear 250ms'); + @include _(transform, scaleY(0)); + @include _(transform-origin, 0 0); + max-height: 0; + visibility: hidden; + + &.open { + @include _(transition, 'transform 250ms ease-in-out, max-height 250ms ease-in-out'); + max-height: 100em; + visibility: visible; + @include _(transform, scaleX(1)); + } +} + @include breakpoint(medium) { body { padding-bottom: 0; @@ -2201,11 +2251,11 @@ html[data-lingua-franca-example="html"] { form { &.flex-form { - display: flex; - align-items: flex-start; + @include _-(display, flex); + @include _(align-items, flex-start); .input-field { - flex: 1; + @include _(flex, 1); } button, .button { @@ -2217,6 +2267,7 @@ html[data-lingua-franca-example="html"] { .number-field, .email-field, + .telephone-field, .text-field { &.big input { font-size: 2em; @@ -2224,8 +2275,8 @@ html[data-lingua-franca-example="html"] { } .flex-column { - display: flex; - align-items: flex-start; + @include _-(display, flex); + @include _(align-items, flex-start); margin-top: 1em; p:first-child { @@ -2233,7 +2284,7 @@ html[data-lingua-franca-example="html"] { } .stretch-item { - flex: 1; + @include _(flex, 1); margin-right: 1em; } } @@ -2537,8 +2588,8 @@ html[data-lingua-franca-example="html"] { } .github { - flex: none; - flex-basis: auto; + @include _(flex, none); + @include _(flex-basis, auto); bottom: 0.5em; float: left; margin-right: 1em; @@ -2548,18 +2599,18 @@ html[data-lingua-franca-example="html"] { margin: 0; } ul.locales { - flex: none; - flex-basis: auto; - flex-grow: 1; + @include _(flex, none); + @include _(flex-basis, auto); + @include _(flex-grow, 1); } } .check-box-field, .radio-button-field { - display: flex; + @include _-(display, flex); label { - flex: 1; + @include _(flex, 1); border: 0.1em solid; border-left: 0; text-align: left; diff --git a/app/controllers/conferences_controller.rb b/app/controllers/conferences_controller.rb index a1f40e2..b07e813 100644 --- a/app/controllers/conferences_controller.rb +++ b/app/controllers/conferences_controller.rb @@ -578,6 +578,20 @@ class ConferencesController < ApplicationController end current_user.save! unless @errors.present? + when :hosting + @registration.can_provide_housing = params[:can_provide_housing].present? + @registration.housing_data = { + address: params[:address], + phone: params[:phone], + space: { + bed_space: params[:bed_space], + floor_space: params[:floor_space], + tent_space: params[:tent_space], + }, + considerations: params[:considerations].keys, + availability: [ params[:first_day], params[:last_day] ], + notes: params[:notes] + } end if @errors.present? @@ -743,11 +757,13 @@ class ConferencesController < ApplicationController :bike => nil, :other => '' ); - @languages = [I18n.locale.to_sym] + @languages = current_user.languages - if @registration.languages - @languages = JSON.parse(@registration.languages).map &:to_sym + if @languages.blank? && @registration.languages.present? + @languages = (@registration.languages.is_a?(String) ? JSON.parse(@registration.languages) : @registration.languages).map &:to_sym end + + @languages ||= [I18n.locale.to_sym] when :workshops @page_title = 'articles.conference_registration.headings.Workshops' @workshops = Workshop.where(conference_id: @this_conference.id) @@ -758,6 +774,12 @@ class ConferencesController < ApplicationController @workshops_in_need = Workshop.where(conference_id: @this_conference.id, needs_facilitators: true) when :contact_info @page_title = 'articles.conference_registration.headings.Contact_Info' + when :hosting + @page_title = 'articles.conference_registration.headings.Hosting' + @hosting_data = @registration.housing_data || {} + @hosting_data['space'] ||= Hash.new + @hosting_data['availability'] ||= Array.new + @hosting_data['considerations'] ||= Array.new when :policy @page_title = 'articles.conference_registration.headings.Policy_Agreement' when :done @@ -1447,10 +1469,14 @@ class ConferencesController < ApplicationController def registration_steps(conference = nil) conference ||= @this_conference || @conference - { - pre: [:policy, :contact_info, :workshops], - open: [:policy, :contact_info, :questions, :payment, :workshops] - }[conference.registration_status] + status = conference.registration_status + return [] unless status == :pre || status == :open + + steps = [:policy, :contact_info, :questions, :hosting, :payment, :workshops] + steps -= [:questions, :payment] unless status == :open + steps -= [:hosting] unless @registration.present? && view_context.same_city?(@registration.city, @conference.location) + + return steps end def required_steps(conference = nil) @@ -1508,11 +1534,23 @@ class ConferencesController < ApplicationController def set_or_create_conference_registration set_conference_registration + return @registration if @registration.present? + @registration ||= ConferenceRegistration.new( conference: @this_conference, user_id: current_user.id, steps_completed: [] ) + last_registration_data = ConferenceRegistration.where(user_id: current_user.id).order(created_at: :desc).limit(1).first + + if last_registration_data.present? + if last_registration_data['languages'].present? && current_user.languages.blank? + current_user.languages = JSON.parse(last_registration_data['languages']) + current_user.save! + end + + @registration.city = last_registration_data.city if last_registration_data.city.present? + end end # Only allow a trusted parameter "white list" through. diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index dfb16c7..88d286d 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -611,6 +611,13 @@ module ApplicationHelper return hash.length > 1 ? _("geography.formats.#{hash.keys.join('_')}", vars: hash) : hash.values.first end + def same_city?(location1, location2) + location1 = location(location1) unless location1.is_a?(String) + location2 = location(location2) unless location2.is_a?(String) + + location1.eql? location2 + end + def show_errors(field) return '' unless @errors && @errors[field].present? @@ -665,6 +672,38 @@ module ApplicationHelper _!((p * 10000).to_i.to_s.gsub(/^(.*)(\d\d)$/, '\1.\2%')) end + def conference_housing_options(conference = nil) + conference ||= @this_conference || @conference + return [] unless conference + + dates = [] + day = conference.start_date - 7.days + last_day = conference.end_date + 7.days + + while day <= last_day + dates << day + day += 1.day + end + + return dates + end + + def conference_housing_options_list(period, conference = nil) + conference ||= @this_conference || @conference + return [] unless conference + + days = [] + + conference_housing_options(conference).each do |day| + belongs_to_periods = [] + belongs_to_periods << :before if day <= conference.start_date + belongs_to_periods << :after if day >= conference.end_date + belongs_to_periods << :during if day >= conference.start_date && day <= conference.end_date + days << [date(day.to_date, :span_same_year_date_1), day] if belongs_to_periods.include?(period) + end + return days + end + def richtext(text, reduce_headings = 2) return '' unless text.present? return _!(text). @@ -704,26 +743,75 @@ module ApplicationHelper return html.html_safe end + def fieldset(name, options = {}, &block) + html = '' + label_id = nil + description_id = nil + + if options[:heading].present? + label_id ||= "#{name.to_s}-label" + html += content_tag(:h3, _(options[:heading], :t), id: label_id) + end + + if options[:help].present? + description_id ||= "#{name.to_s}-desc" + html += content_tag(:div, _(options[:help], :s, 2), class: 'input-field-help', id: description_id) + end + + (html + content_tag(:fieldset, content_tag(:div, class: :fieldgroup, &block).html_safe, + aria: { + labeledby: label_id, + describedby: description_id + } + ) + ).html_safe + end + + def selectfield(name, value, select_options, options = {}) + textfield(name, value, options.merge({type: :select, options: select_options})) + end + + def telephonefield(name, value, options = {}) + textfield(name, value, options.merge({type: :telephone})) + end + + def numberfield(name, value, options = {}) + textfield(name, value, options.merge({type: :number})) + end + def textfield(name, value, options = {}) html = '' description_id = nil if options[:heading].present? description_id ||= "#{name.to_s}-desc" - html += content_tag(:h3, _(options[:heading]), id: description_id) + html += content_tag(:h3, _(options[:heading], :t), id: description_id) + end + + if options[:help].present? + description_id ||= "#{name.to_s}-desc" + html += content_tag(:div, _(options[:help], :s, 2), class: 'input-field-help', id: description_id) end html += show_errors name html += label_tag name - html += text_field_tag(name, value, + input_options = { required: options[:required], lang: options[:lang], + min: options[:min], + max: options[:max], aria: { describedby: description_id } - ) + } + case options[:type] + when :select + html += select_tag(name, options_for_select(options[:options], value), input_options) + else + html += send("#{(options[:type] || :text).to_s}_field_tag", name, value, input_options) + end html = content_tag(:div, html.html_safe, class: [ - 'text-field', + "#{(options[:type] || :text).to_s}-field", 'input-field', options[:big] ? 'big' : nil, (@errors || {})[name].present? ? 'has-error' : nil @@ -738,6 +826,10 @@ module ApplicationHelper checkboxes(name, boxes, [value], label_key, options.merge({radiobuttons: true})) end + def checkbox(name, value, label_key, options = {}) + checkboxes(name, [true], value, label_key, options) + end + def checkboxes(name, boxes, values, label_key, options = {}) html = '' @@ -746,7 +838,7 @@ module ApplicationHelper if options[:heading].present? label_id ||= "#{name.to_s}-label" - html += content_tag(:h3, _(options[:heading]), id: label_id) + html += content_tag(:h3, _(options[:heading], :t), id: label_id) end if options[:help].present? @@ -756,23 +848,24 @@ module ApplicationHelper boxes_html = '' - values = values.present? ? values.map(&:to_s) : [] + is_single = !values.is_a?(Array) + values = values.present? ? values.map(&:to_s) : [] unless is_single boxes = boxes.map(&:to_s) boxes.each do | box | - checked = values.include?(box) - values -= [box] if checked + checked = (is_single ? values.present? : values.include?(box)) + values -= [box] if checked && !is_single id = nil if options[:radiobuttons].present? id = "#{name.to_s}_#{box}" boxes_html += radio_button_tag(name, box, checked) else - id = "#{name.to_s}[#{box}]" - boxes_html += check_box_tag(id, 1, checked) + id = (is_single ? name : "#{name.to_s}[#{box}]") + boxes_html += check_box_tag(id, 1, checked, data: { toggles: options[:toggles] }.compact) end - boxes_html += label_tag(id, _("#{label_key.to_s}.#{box}")) + boxes_html += label_tag(id, _(is_single ? label_key.to_s : "#{label_key.to_s}.#{box}")) end - if options[:other].present? + if options[:other].present? && !is_single id = nil if options[:radiobuttons].present? id = "#{name.to_s}_other" @@ -787,16 +880,19 @@ module ApplicationHelper class: 'other') end - html += content_tag(:fieldset, boxes_html.html_safe, + html += content_tag(:fieldset, content_tag(:div, boxes_html.html_safe, + class: [ + 'check-box-field', + 'input-field', + options[:vertical] ? 'vertical' : nil, + options[:inline] ? 'inline' : nil + ]).html_safe, aria: { labeledby: label_id, describedby: description_id }, - class: [ - 'check-box-field', - 'input-field', - options[:vertical] ? 'vertical' : nil - ]) + class: options[:centered] ? 'centered' : nil + ) return html.html_safe end diff --git a/app/views/conferences/_contact_info.html.haml b/app/views/conferences/_contact_info.html.haml index 789d7fc..54418e8 100644 --- a/app/views/conferences/_contact_info.html.haml +++ b/app/views/conferences/_contact_info.html.haml @@ -3,16 +3,9 @@ %p=_'articles.conference_registration.paragraphs.Contact_Info', :s, 2 = columns(medium: 12) do = form_tag register_path(@this_conference.slug) do - = textfield :name, @name, required: true, heading: 'articles.conference_registration.headings.name' + = textfield :name, @name, required: true, heading: 'articles.conference_registration.headings.name', big: true = textfield :location, (@registration.city || location(lookup_ip_location)), required: true, heading: 'articles.conference_registration.headings.location' - %h3=_'articles.conference_registration.headings.languages','Which languages do you speak?' - - puts @errors.to_json.to_s - .check-box-field.input-field{class: @errors[:languages].present? ? 'has-error' : nil} - - [:en, :es, :fr].each do |language| - = check_box_tag "languages[#{language}]", 1, (@registration.languages || [I18n.locale.to_s]).include?(language.to_s) - = label_tag "languages_#{language}" do - = _"languages.#{language}" - = show_errors :languages + = checkboxes :languages, [:en, :es, :fr], current_user.languages, 'languages', heading: 'articles.conference_registration.headings.languages' .actions.next-prev = button_tag (params[:step] == :save ? :save : :next), value: :contact_info = button_tag :previous, value: :prev_contact_info, class: :subdued, formnovalidate: true diff --git a/app/views/conferences/_hosting.html.haml b/app/views/conferences/_hosting.html.haml new file mode 100644 index 0000000..54a7a2e --- /dev/null +++ b/app/views/conferences/_hosting.html.haml @@ -0,0 +1,24 @@ +- add_stylesheet :editor +- add_inline_script :pen +- add_inline_script :markdown +- add_inline_script :editor + += columns(medium: 12) do + %h2=_(@page_title) += columns(medium: 12) do + = form_tag register_path(@this_conference.slug) do + = checkbox :can_provide_housing, @registration.can_provide_housing, 'articles.conference_registration.can_provide_housing', heading: 'articles.conference_registration.headings.can_provide_housing', help: 'articles.conference_registration.paragraphs.can_provide_housing', inline: true, toggles: 'hosting-options', centered: true + #hosting-options + = textfield :address, @hosting_data['address'], required: true, heading: 'articles.conference_registration.headings.host.address', help: 'articles.conference_registration.paragraphs.host.address' + = telephonefield :phone, @hosting_data['phone'], required: true + = fieldset :space, heading: 'articles.conference_registration.headings.host.space', help: 'articles.conference_registration.paragraphs.host.space' do + - [:bed_space, :floor_space, :tent_space].each do | space | + = numberfield space, @hosting_data['space'][space.to_s] || 0, min: 0, required: true + = fieldset :hosting_dates, heading: 'articles.conference_registration.headings.host.availability', help: 'articles.conference_registration.paragraphs.host.availability' do + = selectfield :first_day, @hosting_data['availability'][0] || @this_conference.start_date, conference_housing_options_list(:before) + = selectfield :last_day, @hosting_data['availability'][1] || @this_conference.start_date, conference_housing_options_list(:after) + = checkboxes :considerations, [:vegan, :smoking, :quiet], @hosting_data['considerations'], 'articles.conference_registration.host.considerations', heading: 'articles.conference_registration.headings.host.considerations', help: 'articles.conference_registration.paragraphs.host.considerations', vertical: true + = textarea :notes, @hosting_data['notes'], heading: 'articles.conference_registration.headings.host.notes', help: 'articles.conference_registration.paragraphs.host.notes' + .actions.next-prev + = button_tag (params[:step] == :save ? :save : :next), value: :hosting + = button_tag :previous, value: :prev_contact_info, class: :subdued, formnovalidate: true diff --git a/app/views/conferences/register.html.haml b/app/views/conferences/register.html.haml index 70172fc..7663223 100644 --- a/app/views/conferences/register.html.haml +++ b/app/views/conferences/register.html.haml @@ -1,5 +1,5 @@ = render :partial => 'page_header', :locals => {:page_key => 'Conference_Registration'} -- if (steps = current_registration_steps) +- if (steps = current_registration_steps(@registration)) = row id: 'registration-steps', class: 'flow-steps' do = columns do %ul diff --git a/config/locales/en.yml b/config/locales/en.yml index 83c2533..c38cc98 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -5328,11 +5328,19 @@ en: fees_paid: Fees Paid Contact_Info: Contact Info contact_info: Contact Info + hosting: Hosting Add_Workshop: Propose a Workshop Workshops_Looking_For_Facilitators: Workshops Looking for Facilitators All_Workshops: All Workshops Pre_Registration_Details: Pre-Registration is now open! Verify_Account: Verify your account + Hosting: Hosting + can_provide_housing: Can you provide housing to attendees visiting the city? + host: + considerations: Special Considerations + space: Available Space + availability: Availability + address: Address paragraphs: Policy_Agreement: Ensuring that all attendees feel welcome, safe, and respected at all times is especially important to us all. Please ensure that you have fully read and understand our safer spaces policy below, if you have any questions or concerns you can reach out to the organizers at any time. Confirm_Agreement: By clicking the "I Agree" button, you are pledging to do @@ -5378,6 +5386,19 @@ en: Pre_Registration_Details: By completing the pre-registration process you are letting us know that you are interested in coming, it allows us to contact you when we have news, and lets us better plan by knowing who might be coming. Once registration is fully open, we will need to ask a few more questions and you can confirm whether or not you will actually be coming. Verify_Account: In order to confirm that you are a real person and that we will be able to contact you later, please verify your email address. Before continuing with pre-registration, we will send you an email that will allow you to continue with the process. facebook_sign_in: Alternatively you can sign in using your Facebook account and skip waiting for us to send you an email. + can_provide_housing: Hosting visiting conference attendees is an important part of Bike!Bike!, it allows many people who would not normally be able to afford the cost of accommodations the chance to come to the conference and lets attendees really get to know our city and its residents. You will need to grant access to your home to guests overnight keeping in mind that events can sometimes go late into the evening. If your home will not be accessible during the day you should make sure to clearly communicate this with your guests. + host: + address: Your address and phone number will be shared with your guests and conference organizers. + space: How much space do you have to share? + availability: The most common arrival and departure dates for attendees are the first and last day of the conference but people often arrive earlier or later. When will your space be available? + considerations: Organizers will do their best to match up hosts and guests, what considerations should organizers keep in mind when selecting guests to stay in your home? + notes: Leave a message for organizers should take into consideration when selecting guests for your household. + host: + considerations: + vegan: Vegan or vegetarian only + smoking: Smoking is permitted + quiet: Quiet household + can_provide_housing: I can provide housing questions: bike: large: Large @@ -5546,6 +5567,13 @@ en: content: Content notes: Notes message: 'Your Message:' + address: Street Address + phone: Phone number + bed_space: Bed/Couch Spaec + floor_space: Floor Space + tent_space: Tent Space + first_day: From + last_day: To actions: generic: login: Sign In diff --git a/db/migrate/20160604221121_add_can_provide_housing_to_conference_registrations.rb b/db/migrate/20160604221121_add_can_provide_housing_to_conference_registrations.rb new file mode 100644 index 0000000..80b544f --- /dev/null +++ b/db/migrate/20160604221121_add_can_provide_housing_to_conference_registrations.rb @@ -0,0 +1,5 @@ +class AddCanProvideHousingToConferenceRegistrations < ActiveRecord::Migration + def change + add_column :conference_registrations, :can_provide_housing, :boolean + end +end diff --git a/db/migrate/20160604221248_add_housing_data_to_conference_registrations.rb b/db/migrate/20160604221248_add_housing_data_to_conference_registrations.rb new file mode 100644 index 0000000..7fbdb7c --- /dev/null +++ b/db/migrate/20160604221248_add_housing_data_to_conference_registrations.rb @@ -0,0 +1,5 @@ +class AddHousingDataToConferenceRegistrations < ActiveRecord::Migration + def change + add_column :conference_registrations, :housing_data, :json + end +end diff --git a/db/migrate/20160604221432_add_locale_to_users.rb b/db/migrate/20160604221432_add_locale_to_users.rb new file mode 100644 index 0000000..838ef11 --- /dev/null +++ b/db/migrate/20160604221432_add_locale_to_users.rb @@ -0,0 +1,5 @@ +class AddLocaleToUsers < ActiveRecord::Migration + def change + add_column :users, :locale, :string + end +end diff --git a/db/schema.rb b/db/schema.rb index d05e436..397da86 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160530175805) do +ActiveRecord::Schema.define(version: 20160604221432) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -83,6 +83,8 @@ ActiveRecord::Schema.define(version: 20160530175805) do t.string "food" t.string "highest_step" t.json "steps_completed" + t.boolean "can_provide_housing" + t.json "housing_data" end create_table "conference_types", force: :cascade do |t| @@ -321,6 +323,7 @@ ActiveRecord::Schema.define(version: 20160530175805) do t.string "lastname" t.boolean "is_translator" t.json "languages" + t.string "locale" end add_index "users", ["activation_token"], name: "index_users_on_activation_token", using: :btree