├── .gitignore ├── .ruby-version ├── Gemfile ├── Gemfile.lock ├── Procfile ├── README.md ├── Rakefile ├── app ├── assets │ ├── config │ │ └── manifest.js │ ├── images │ │ ├── .keep │ │ ├── background.jpg │ │ ├── logo.png │ │ └── pillow.jpg │ ├── javascripts │ │ ├── application.js │ │ ├── cable.js │ │ ├── channels │ │ │ └── .keep │ │ ├── google_maps_autocomplete.js │ │ ├── init_attachinary.js │ │ ├── jquery-sticky.js │ │ └── sticky_map.js │ └── stylesheets │ │ ├── README.md │ │ ├── application.scss │ │ ├── components │ │ ├── _alert.scss │ │ ├── _avatars.scss │ │ ├── _badges.scss │ │ ├── _button.scss │ │ ├── _cards.scss │ │ ├── _form.scss │ │ ├── _images.scss │ │ ├── _index.scss │ │ └── _staticmap.scss │ │ ├── config │ │ ├── _bootstrap_variables.scss │ │ └── _variables.scss │ │ ├── layout │ │ ├── _footer.scss │ │ ├── _index.scss │ │ ├── _navbar.scss │ │ └── _utilities.scss │ │ ├── pages │ │ ├── _bed_show.scss │ │ ├── _beds_form.scss │ │ ├── _beds_index.scss │ │ ├── _edit_bed.scss │ │ ├── _home.scss │ │ ├── _index.scss │ │ ├── _login.scss │ │ ├── _my_booking.scss │ │ └── _signup.scss │ │ └── vendor │ │ ├── _animation_cheat_sheet.scss │ │ └── _index.scss ├── channels │ └── application_cable │ │ ├── channel.rb │ │ └── connection.rb ├── controllers │ ├── application_controller.rb │ ├── beds_controller.rb │ ├── bookings_controller.rb │ ├── concerns │ │ └── .keep │ ├── my │ │ ├── beds_controller.rb │ │ └── bookings_controller.rb │ ├── pages_controller.rb │ └── reviews_controller.rb ├── helpers │ ├── application_helper.rb │ ├── beds_helper.rb │ ├── bookings_helper.rb │ └── reviews_helper.rb ├── jobs │ └── application_job.rb ├── mailers │ └── application_mailer.rb ├── models │ ├── application_record.rb │ ├── bed.rb │ ├── booking.rb │ ├── concerns │ │ └── .keep │ ├── review.rb │ └── user.rb └── views │ ├── beds │ ├── edit.html.erb │ ├── index.html.erb │ ├── new.html.erb │ └── show.html.erb │ ├── bookings │ ├── index.html.erb │ └── show.html.erb │ ├── devise │ ├── confirmations │ │ └── new.html.erb │ ├── mailer │ │ ├── confirmation_instructions.html.erb │ │ ├── password_change.html.erb │ │ ├── reset_password_instructions.html.erb │ │ └── unlock_instructions.html.erb │ ├── passwords │ │ ├── edit.html.erb │ │ └── new.html.erb │ ├── registrations │ │ ├── edit.html.erb │ │ └── new.html.erb │ ├── sessions │ │ └── new.html.erb │ ├── shared │ │ └── _links.html.erb │ └── unlocks │ │ └── new.html.erb │ ├── layouts │ ├── application.html.erb │ ├── mailer.html.erb │ └── mailer.text.erb │ ├── my │ ├── beds │ │ └── index.html.erb │ └── bookings │ │ └── index.html.erb │ ├── pages │ └── home.html.erb │ ├── reviews │ └── _form.html.erb │ └── shared │ ├── _flashes.html.erb │ ├── _footer.html.erb │ └── _navbar.html.erb ├── bin ├── bundle ├── figaro ├── rails ├── rake ├── setup ├── spring └── update ├── config.ru ├── config ├── application.rb ├── boot.rb ├── cable.yml ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── application_controller_renderer.rb │ ├── assets.rb │ ├── backtrace_silencers.rb │ ├── cookies_serializer.rb │ ├── devise.rb │ ├── filter_parameter_logging.rb │ ├── geocoder.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── new_framework_defaults.rb │ ├── session_store.rb │ ├── simple_form.rb │ ├── simple_form_bootstrap.rb │ └── wrap_parameters.rb ├── locales │ ├── devise.en.yml │ ├── en.yml │ └── simple_form.en.yml ├── puma.rb ├── routes.rb ├── secrets.yml └── spring.rb ├── db ├── migrate │ ├── 20170213145054_devise_create_users.rb │ ├── 20170213153159_add_column_to_user.rb │ ├── 20170213154859_create_beds.rb │ ├── 20170213155555_create_bookings.rb │ ├── 20170213172408_add_column_to_bed.rb │ ├── 20170213172524_add_columns_to_bed.rb │ ├── 20170214102719_create_attachinary_tables.attachinary.rb │ ├── 20170214110259_add_pillow_to_beds.rb │ ├── 20170214110645_add_columns_to_beds.rb │ ├── 20170215102014_add_coordinates_to_beds.rb │ └── 20170216105543_create_reviews.rb ├── schema.rb └── seeds.rb ├── lib ├── assets │ └── .keep ├── tasks │ └── .keep └── templates │ └── erb │ └── scaffold │ └── _form.html.erb ├── log └── .keep ├── public ├── 404.html ├── 422.html ├── 500.html ├── apple-touch-icon-precomposed.png ├── apple-touch-icon.png ├── background-try.jpg ├── favicon.ico ├── feet.jpg ├── giphy.gif ├── hearts.gif ├── logo-pink.png └── robots.txt └── vendor └── assets ├── javascripts └── .keep └── stylesheets └── .keep /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle 2 | log/*.log 3 | tmp/**/* 4 | tmp/* 5 | *.swp 6 | .DS_Store 7 | public/assets 8 | 9 | # Ignore application configuration 10 | /config/application.yml 11 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | 2.3.3 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | ruby '2.3.3' 3 | 4 | gem 'rails', '5.0.1' 5 | gem 'puma' 6 | gem 'pg' 7 | gem 'figaro' 8 | gem 'jbuilder', '~> 2.0' 9 | gem 'redis' 10 | gem 'devise' 11 | gem 'cloudinary', '1.1.0' 12 | 13 | gem 'sass-rails' 14 | gem 'jquery-rails' 15 | gem 'uglifier' 16 | gem 'bootstrap-sass' 17 | gem 'font-awesome-sass' 18 | gem 'simple_form' 19 | gem 'autoprefixer-rails' 20 | gem 'country_select' 21 | gem "attachinary", github: "assembler/attachinary" 22 | gem "jquery-fileupload-rails" 23 | gem "geocoder" 24 | gem "coffee-rails" 25 | gem "gmaps4rails" 26 | 27 | source 'https://rails-assets.org' do 28 | gem "rails-assets-underscore" 29 | end 30 | 31 | source "https://rails-assets.org" do 32 | gem 'rails-assets-bootstrap-datepicker' 33 | end 34 | 35 | 36 | group :development, :test do 37 | gem 'binding_of_caller' 38 | gem 'better_errors' 39 | 40 | gem 'pry-byebug' 41 | gem 'pry-rails' 42 | gem 'spring' 43 | gem 'listen', '~> 3.0.5' 44 | gem 'spring-watcher-listen', '~> 2.0.0' 45 | end 46 | 47 | 48 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GIT 2 | remote: git://github.com/assembler/attachinary.git 3 | revision: 98a895be22edc74b1928ffa3ae116d24bd9818fd 4 | specs: 5 | attachinary (1.3.1) 6 | cloudinary (~> 1.1.0) 7 | rails (>= 3.2) 8 | 9 | GEM 10 | remote: https://rubygems.org/ 11 | remote: https://rails-assets.org/ 12 | specs: 13 | actioncable (5.0.1) 14 | actionpack (= 5.0.1) 15 | nio4r (~> 1.2) 16 | websocket-driver (~> 0.6.1) 17 | actionmailer (5.0.1) 18 | actionpack (= 5.0.1) 19 | actionview (= 5.0.1) 20 | activejob (= 5.0.1) 21 | mail (~> 2.5, >= 2.5.4) 22 | rails-dom-testing (~> 2.0) 23 | actionpack (5.0.1) 24 | actionview (= 5.0.1) 25 | activesupport (= 5.0.1) 26 | rack (~> 2.0) 27 | rack-test (~> 0.6.3) 28 | rails-dom-testing (~> 2.0) 29 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 30 | actionview (5.0.1) 31 | activesupport (= 5.0.1) 32 | builder (~> 3.1) 33 | erubis (~> 2.7.0) 34 | rails-dom-testing (~> 2.0) 35 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 36 | activejob (5.0.1) 37 | activesupport (= 5.0.1) 38 | globalid (>= 0.3.6) 39 | activemodel (5.0.1) 40 | activesupport (= 5.0.1) 41 | activerecord (5.0.1) 42 | activemodel (= 5.0.1) 43 | activesupport (= 5.0.1) 44 | arel (~> 7.0) 45 | activesupport (5.0.1) 46 | concurrent-ruby (~> 1.0, >= 1.0.2) 47 | i18n (~> 0.7) 48 | minitest (~> 5.1) 49 | tzinfo (~> 1.1) 50 | arel (7.1.4) 51 | autoprefixer-rails (6.7.2) 52 | execjs 53 | aws_cf_signer (0.1.3) 54 | bcrypt (3.1.11) 55 | better_errors (2.1.1) 56 | coderay (>= 1.0.0) 57 | erubis (>= 2.6.6) 58 | rack (>= 0.9.0) 59 | binding_of_caller (0.7.2) 60 | debug_inspector (>= 0.0.1) 61 | bootstrap-sass (3.3.7) 62 | autoprefixer-rails (>= 5.2.1) 63 | sass (>= 3.3.4) 64 | builder (3.2.3) 65 | byebug (9.0.6) 66 | cloudinary (1.1.0) 67 | aws_cf_signer 68 | rest-client 69 | coderay (1.1.1) 70 | coffee-rails (4.2.1) 71 | coffee-script (>= 2.2.0) 72 | railties (>= 4.0.0, < 5.2.x) 73 | coffee-script (2.4.1) 74 | coffee-script-source 75 | execjs 76 | coffee-script-source (1.12.2) 77 | concurrent-ruby (1.0.4) 78 | countries (1.2.5) 79 | currencies (~> 0.4.2) 80 | i18n_data (~> 0.7.0) 81 | country_select (2.5.2) 82 | countries (~> 1.2.0) 83 | sort_alphabetical (~> 1.0) 84 | currencies (0.4.2) 85 | debug_inspector (0.0.2) 86 | devise (4.2.0) 87 | bcrypt (~> 3.0) 88 | orm_adapter (~> 0.1) 89 | railties (>= 4.1.0, < 5.1) 90 | responders 91 | warden (~> 1.2.3) 92 | domain_name (0.5.20161129) 93 | unf (>= 0.0.5, < 1.0.0) 94 | erubis (2.7.0) 95 | execjs (2.7.0) 96 | ffi (1.9.17) 97 | figaro (1.1.1) 98 | thor (~> 0.14) 99 | font-awesome-sass (4.7.0) 100 | sass (>= 3.2) 101 | geocoder (1.4.3) 102 | globalid (0.3.7) 103 | activesupport (>= 4.1.0) 104 | gmaps4rails (2.1.2) 105 | http-cookie (1.0.3) 106 | domain_name (~> 0.5) 107 | i18n (0.8.0) 108 | i18n_data (0.7.0) 109 | jbuilder (2.6.1) 110 | activesupport (>= 3.0.0, < 5.1) 111 | multi_json (~> 1.2) 112 | jquery-fileupload-rails (0.4.7) 113 | actionpack (>= 3.1) 114 | railties (>= 3.1) 115 | sass (>= 3.2) 116 | jquery-rails (4.2.2) 117 | rails-dom-testing (>= 1, < 3) 118 | railties (>= 4.2.0) 119 | thor (>= 0.14, < 2.0) 120 | listen (3.0.8) 121 | rb-fsevent (~> 0.9, >= 0.9.4) 122 | rb-inotify (~> 0.9, >= 0.9.7) 123 | loofah (2.0.3) 124 | nokogiri (>= 1.5.9) 125 | mail (2.6.4) 126 | mime-types (>= 1.16, < 4) 127 | method_source (0.8.2) 128 | mime-types (3.1) 129 | mime-types-data (~> 3.2015) 130 | mime-types-data (3.2016.0521) 131 | mini_portile2 (2.1.0) 132 | minitest (5.10.1) 133 | multi_json (1.12.1) 134 | netrc (0.11.0) 135 | nio4r (1.2.1) 136 | nokogiri (1.7.0.1) 137 | mini_portile2 (~> 2.1.0) 138 | orm_adapter (0.5.0) 139 | pg (0.19.0) 140 | pry (0.10.4) 141 | coderay (~> 1.1.0) 142 | method_source (~> 0.8.1) 143 | slop (~> 3.4) 144 | pry-byebug (3.4.2) 145 | byebug (~> 9.0) 146 | pry (~> 0.10) 147 | pry-rails (0.3.4) 148 | pry (>= 0.9.10) 149 | puma (3.7.0) 150 | rack (2.0.1) 151 | rack-test (0.6.3) 152 | rack (>= 1.0) 153 | rails (5.0.1) 154 | actioncable (= 5.0.1) 155 | actionmailer (= 5.0.1) 156 | actionpack (= 5.0.1) 157 | actionview (= 5.0.1) 158 | activejob (= 5.0.1) 159 | activemodel (= 5.0.1) 160 | activerecord (= 5.0.1) 161 | activesupport (= 5.0.1) 162 | bundler (>= 1.3.0, < 2.0) 163 | railties (= 5.0.1) 164 | sprockets-rails (>= 2.0.0) 165 | rails-assets-bootstrap-datepicker (1.6.4) 166 | rails-assets-jquery (>= 1.7.1) 167 | rails-assets-jquery (3.1.1) 168 | rails-assets-underscore (1.8.3) 169 | rails-dom-testing (2.0.2) 170 | activesupport (>= 4.2.0, < 6.0) 171 | nokogiri (~> 1.6) 172 | rails-html-sanitizer (1.0.3) 173 | loofah (~> 2.0) 174 | railties (5.0.1) 175 | actionpack (= 5.0.1) 176 | activesupport (= 5.0.1) 177 | method_source 178 | rake (>= 0.8.7) 179 | thor (>= 0.18.1, < 2.0) 180 | rake (12.0.0) 181 | rb-fsevent (0.9.8) 182 | rb-inotify (0.9.8) 183 | ffi (>= 0.5.0) 184 | redis (3.3.3) 185 | responders (2.3.0) 186 | railties (>= 4.2.0, < 5.1) 187 | rest-client (2.0.0) 188 | http-cookie (>= 1.0.2, < 2.0) 189 | mime-types (>= 1.16, < 4.0) 190 | netrc (~> 0.8) 191 | sass (3.4.23) 192 | sass-rails (5.0.6) 193 | railties (>= 4.0.0, < 6) 194 | sass (~> 3.1) 195 | sprockets (>= 2.8, < 4.0) 196 | sprockets-rails (>= 2.0, < 4.0) 197 | tilt (>= 1.1, < 3) 198 | simple_form (3.4.0) 199 | actionpack (> 4, < 5.1) 200 | activemodel (> 4, < 5.1) 201 | slop (3.6.0) 202 | sort_alphabetical (1.1.0) 203 | unicode_utils (>= 1.2.2) 204 | spring (2.0.1) 205 | activesupport (>= 4.2) 206 | spring-watcher-listen (2.0.1) 207 | listen (>= 2.7, < 4.0) 208 | spring (>= 1.2, < 3.0) 209 | sprockets (3.7.1) 210 | concurrent-ruby (~> 1.0) 211 | rack (> 1, < 3) 212 | sprockets-rails (3.2.0) 213 | actionpack (>= 4.0) 214 | activesupport (>= 4.0) 215 | sprockets (>= 3.0.0) 216 | thor (0.19.4) 217 | thread_safe (0.3.5) 218 | tilt (2.0.6) 219 | tzinfo (1.2.2) 220 | thread_safe (~> 0.1) 221 | uglifier (3.0.4) 222 | execjs (>= 0.3.0, < 3) 223 | unf (0.1.4) 224 | unf_ext 225 | unf_ext (0.0.7.2) 226 | unicode_utils (1.4.0) 227 | warden (1.2.7) 228 | rack (>= 1.0) 229 | websocket-driver (0.6.5) 230 | websocket-extensions (>= 0.1.0) 231 | websocket-extensions (0.1.2) 232 | 233 | PLATFORMS 234 | ruby 235 | 236 | DEPENDENCIES 237 | attachinary! 238 | autoprefixer-rails 239 | better_errors 240 | binding_of_caller 241 | bootstrap-sass 242 | cloudinary (= 1.1.0) 243 | coffee-rails 244 | country_select 245 | devise 246 | figaro 247 | font-awesome-sass 248 | geocoder 249 | gmaps4rails 250 | jbuilder (~> 2.0) 251 | jquery-fileupload-rails 252 | jquery-rails 253 | listen (~> 3.0.5) 254 | pg 255 | pry-byebug 256 | pry-rails 257 | puma 258 | rails (= 5.0.1) 259 | rails-assets-bootstrap-datepicker! 260 | rails-assets-underscore! 261 | redis 262 | sass-rails 263 | simple_form 264 | spring 265 | spring-watcher-listen (~> 2.0.0) 266 | uglifier 267 | 268 | RUBY VERSION 269 | ruby 2.3.3p222 270 | 271 | BUNDLED WITH 272 | 1.13.7 273 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: bundle exec puma -C config/puma.rb 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Rails app generated with [lewagon/rails-templates](https://github.com/lewagon/rails-templates), created by the [Le Wagon coding bootcamp](https://www.lewagon.com) team. 2 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative 'config/application' 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/assets/config/manifest.js: -------------------------------------------------------------------------------- 1 | //= link_tree ../images 2 | //= link_directory ../javascripts .js 3 | //= link_directory ../stylesheets .css 4 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/app/assets/images/.keep -------------------------------------------------------------------------------- /app/assets/images/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/app/assets/images/background.jpg -------------------------------------------------------------------------------- /app/assets/images/logo.png: -------------------------------------------------------------------------------- 1 | 404: Not Found 2 | -------------------------------------------------------------------------------- /app/assets/images/pillow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/app/assets/images/pillow.jpg -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | //= require jquery 2 | //= require jquery_ujs 3 | //= require bootstrap-sprockets 4 | //= require underscore 5 | //= require gmaps/google 6 | //= require bootstrap-datepicker 7 | //= require_tree . 8 | 9 | // app/assets/javascripts/application.js 10 | 11 | //= require jquery-fileupload/basic 12 | //= require cloudinary/jquery.cloudinary 13 | //= require attachinary 14 | 15 | $(document).ready(function() { 16 | $('.datepicker').datepicker({ 17 | format: "dd/mm/yyyy", 18 | weekStart: 1, 19 | autoclose: true 20 | }); 21 | }); 22 | -------------------------------------------------------------------------------- /app/assets/javascripts/cable.js: -------------------------------------------------------------------------------- 1 | // Action Cable provides the framework to deal with WebSockets in Rails. 2 | // You can generate new channels where WebSocket features live using the rails generate channel command. 3 | // 4 | //= require action_cable 5 | //= require_self 6 | //= require_tree ./channels 7 | 8 | (function() { 9 | this.App || (this.App = {}); 10 | 11 | App.cable = ActionCable.createConsumer(); 12 | 13 | }).call(this); 14 | -------------------------------------------------------------------------------- /app/assets/javascripts/channels/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/app/assets/javascripts/channels/.keep -------------------------------------------------------------------------------- /app/assets/javascripts/google_maps_autocomplete.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | var bed_address = $('#bed_address').get(0); 3 | 4 | if (bed_address) { 5 | var autocomplete = new google.maps.places.Autocomplete(bed_address, { types: ['geocode'] }); 6 | google.maps.event.addListener(autocomplete, 'place_changed', onPlaceChanged); 7 | google.maps.event.addDomListener(bed_address, 'keydown', function(e) { 8 | if (e.keyCode == 13) { 9 | e.preventDefault(); // Do not submit the form on Enter. 10 | } 11 | }); 12 | } 13 | }); 14 | 15 | function onPlaceChanged() { 16 | var place = this.getPlace(); 17 | var components = getAddressComponents(place); 18 | 19 | $('#bed_address').trigger('blur').val(components.address); 20 | $('#bed_zip_code').val(components.zip_code); 21 | $('#bed_city').val(components.city); 22 | if (components.country_code) { 23 | $('#bed_country').val(components.country_code); 24 | } 25 | } 26 | 27 | function getAddressComponents(place) { 28 | // If you want lat/lng, you can look at: 29 | // - place.geometry.location.lat() 30 | // - place.geometry.location.lng() 31 | 32 | var street_number = null; 33 | var route = null; 34 | var zip_code = null; 35 | var city = null; 36 | var country_code = null; 37 | for (var i in place.address_components) { 38 | var component = place.address_components[i]; 39 | for (var j in component.types) { 40 | var type = component.types[j]; 41 | if (type == 'street_number') { 42 | street_number = component.long_name; 43 | } else if (type == 'route') { 44 | route = component.long_name; 45 | } else if (type == 'postal_code') { 46 | zip_code = component.long_name; 47 | } else if (type == 'locality') { 48 | city = component.long_name; 49 | } else if (type == 'country') { 50 | country_code = component.short_name; 51 | } 52 | } 53 | } 54 | 55 | return { 56 | address: street_number == null ? route : (street_number + ' ' + route), 57 | zip_code: zip_code, 58 | city: city, 59 | country_code: country_code 60 | }; 61 | } 62 | -------------------------------------------------------------------------------- /app/assets/javascripts/init_attachinary.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | $('.attachinary-input').attachinary(); 3 | }); 4 | -------------------------------------------------------------------------------- /app/assets/javascripts/jquery-sticky.js: -------------------------------------------------------------------------------- 1 | // Sticky Plugin v1.0.4 for jQuery 2 | // ============= 3 | // Author: Anthony Garand 4 | // Improvements by German M. Bravo (Kronuz) and Ruud Kamphuis (ruudk) 5 | // Improvements by Leonardo C. Daronco (daronco) 6 | // Created: 02/14/2011 7 | // Date: 07/20/2015 8 | // Website: http://stickyjs.com/ 9 | // Description: Makes an element on the page stick on the screen as you scroll 10 | // It will only set the 'top' and 'position' of your element, you 11 | // might need to adjust the width in some cases. 12 | 13 | (function (factory) { 14 | if (typeof define === 'function' && define.amd) { 15 | // AMD. Register as an anonymous module. 16 | define(['jquery'], factory); 17 | } else if (typeof module === 'object' && module.exports) { 18 | // Node/CommonJS 19 | module.exports = factory(require('jquery')); 20 | } else { 21 | // Browser globals 22 | factory(jQuery); 23 | } 24 | }(function ($) { 25 | var slice = Array.prototype.slice; // save ref to original slice() 26 | var splice = Array.prototype.splice; // save ref to original slice() 27 | 28 | var defaults = { 29 | topSpacing: 0, 30 | bottomSpacing: 0, 31 | className: 'is-sticky', 32 | wrapperClassName: 'sticky-wrapper', 33 | center: false, 34 | getWidthFrom: '', 35 | widthFromWrapper: true, // works only when .getWidthFrom is empty 36 | responsiveWidth: false, 37 | zIndex: 'auto' 38 | }, 39 | $window = $(window), 40 | $document = $(document), 41 | sticked = [], 42 | windowHeight = $window.height(), 43 | scroller = function() { 44 | var scrollTop = $window.scrollTop(), 45 | documentHeight = $document.height(), 46 | dwh = documentHeight - windowHeight, 47 | extra = (scrollTop > dwh) ? dwh - scrollTop : 0; 48 | 49 | for (var i = 0, l = sticked.length; i < l; i++) { 50 | var s = sticked[i], 51 | elementTop = s.stickyWrapper.offset().top, 52 | etse = elementTop - s.topSpacing - extra; 53 | 54 | //update height in case of dynamic content 55 | s.stickyWrapper.css('height', s.stickyElement.outerHeight()); 56 | 57 | if (scrollTop <= etse) { 58 | if (s.currentTop !== null) { 59 | s.stickyElement 60 | .css({ 61 | 'width': '', 62 | 'position': '', 63 | 'top': '', 64 | 'z-index': '' 65 | }); 66 | s.stickyElement.parent().removeClass(s.className); 67 | s.stickyElement.trigger('sticky-end', [s]); 68 | s.currentTop = null; 69 | } 70 | } 71 | else { 72 | var newTop = documentHeight - s.stickyElement.outerHeight() 73 | - s.topSpacing - s.bottomSpacing - scrollTop - extra; 74 | if (newTop < 0) { 75 | newTop = newTop + s.topSpacing; 76 | } else { 77 | newTop = s.topSpacing; 78 | } 79 | if (s.currentTop !== newTop) { 80 | var newWidth; 81 | if (s.getWidthFrom) { 82 | newWidth = $(s.getWidthFrom).width() || null; 83 | } else if (s.widthFromWrapper) { 84 | newWidth = s.stickyWrapper.width(); 85 | } 86 | if (newWidth == null) { 87 | newWidth = s.stickyElement.width(); 88 | } 89 | s.stickyElement 90 | .css('width', newWidth) 91 | .css('position', 'fixed') 92 | .css('top', newTop) 93 | .css('z-index', s.zIndex); 94 | 95 | s.stickyElement.parent().addClass(s.className); 96 | 97 | if (s.currentTop === null) { 98 | s.stickyElement.trigger('sticky-start', [s]); 99 | } else { 100 | // sticky is started but it have to be repositioned 101 | s.stickyElement.trigger('sticky-update', [s]); 102 | } 103 | 104 | if (s.currentTop === s.topSpacing && s.currentTop > newTop || s.currentTop === null && newTop < s.topSpacing) { 105 | // just reached bottom || just started to stick but bottom is already reached 106 | s.stickyElement.trigger('sticky-bottom-reached', [s]); 107 | } else if(s.currentTop !== null && newTop === s.topSpacing && s.currentTop < newTop) { 108 | // sticky is started && sticked at topSpacing && overflowing from top just finished 109 | s.stickyElement.trigger('sticky-bottom-unreached', [s]); 110 | } 111 | 112 | s.currentTop = newTop; 113 | } 114 | 115 | // Check if sticky has reached end of container and stop sticking 116 | var stickyWrapperContainer = s.stickyWrapper.parent(); 117 | var unstick = (s.stickyElement.offset().top + s.stickyElement.outerHeight() >= stickyWrapperContainer.offset().top + stickyWrapperContainer.outerHeight()) && (s.stickyElement.offset().top <= s.topSpacing); 118 | 119 | if( unstick ) { 120 | s.stickyElement 121 | .css('position', 'absolute') 122 | .css('top', '') 123 | .css('bottom', 0) 124 | .css('z-index', ''); 125 | } else { 126 | s.stickyElement 127 | .css('position', 'fixed') 128 | .css('top', newTop) 129 | .css('bottom', '') 130 | .css('z-index', s.zIndex); 131 | } 132 | } 133 | } 134 | }, 135 | resizer = function() { 136 | windowHeight = $window.height(); 137 | 138 | for (var i = 0, l = sticked.length; i < l; i++) { 139 | var s = sticked[i]; 140 | var newWidth = null; 141 | if (s.getWidthFrom) { 142 | if (s.responsiveWidth) { 143 | newWidth = $(s.getWidthFrom).width(); 144 | } 145 | } else if(s.widthFromWrapper) { 146 | newWidth = s.stickyWrapper.width(); 147 | } 148 | if (newWidth != null) { 149 | s.stickyElement.css('width', newWidth); 150 | } 151 | } 152 | }, 153 | methods = { 154 | init: function(options) { 155 | return this.each(function() { 156 | var o = $.extend({}, defaults, options); 157 | var stickyElement = $(this); 158 | 159 | var stickyId = stickyElement.attr('id'); 160 | var wrapperId = stickyId ? stickyId + '-' + defaults.wrapperClassName : defaults.wrapperClassName; 161 | var wrapper = $('
') 162 | .attr('id', wrapperId) 163 | .addClass(o.wrapperClassName); 164 | 165 | stickyElement.wrapAll(function() { 166 | if ($(this).parent("#" + wrapperId).length == 0) { 167 | return wrapper; 168 | } 169 | }); 170 | 171 | var stickyWrapper = stickyElement.parent(); 172 | 173 | if (o.center) { 174 | stickyWrapper.css({width:stickyElement.outerWidth(),marginLeft:"auto",marginRight:"auto"}); 175 | } 176 | 177 | if (stickyElement.css("float") === "right") { 178 | stickyElement.css({"float":"none"}).parent().css({"float":"right"}); 179 | } 180 | 181 | o.stickyElement = stickyElement; 182 | o.stickyWrapper = stickyWrapper; 183 | o.currentTop = null; 184 | 185 | sticked.push(o); 186 | 187 | methods.setWrapperHeight(this); 188 | methods.setupChangeListeners(this); 189 | }); 190 | }, 191 | 192 | setWrapperHeight: function(stickyElement) { 193 | var element = $(stickyElement); 194 | var stickyWrapper = element.parent(); 195 | if (stickyWrapper) { 196 | stickyWrapper.css('height', element.outerHeight()); 197 | } 198 | }, 199 | 200 | setupChangeListeners: function(stickyElement) { 201 | if (window.MutationObserver) { 202 | var mutationObserver = new window.MutationObserver(function(mutations) { 203 | if (mutations[0].addedNodes.length || mutations[0].removedNodes.length) { 204 | methods.setWrapperHeight(stickyElement); 205 | } 206 | }); 207 | mutationObserver.observe(stickyElement, {subtree: true, childList: true}); 208 | } else { 209 | if (window.addEventListener) { 210 | stickyElement.addEventListener('DOMNodeInserted', function() { 211 | methods.setWrapperHeight(stickyElement); 212 | }, false); 213 | stickyElement.addEventListener('DOMNodeRemoved', function() { 214 | methods.setWrapperHeight(stickyElement); 215 | }, false); 216 | } else if (window.attachEvent) { 217 | stickyElement.attachEvent('onDOMNodeInserted', function() { 218 | methods.setWrapperHeight(stickyElement); 219 | }); 220 | stickyElement.attachEvent('onDOMNodeRemoved', function() { 221 | methods.setWrapperHeight(stickyElement); 222 | }); 223 | } 224 | } 225 | }, 226 | update: scroller, 227 | unstick: function(options) { 228 | return this.each(function() { 229 | var that = this; 230 | var unstickyElement = $(that); 231 | 232 | var removeIdx = -1; 233 | var i = sticked.length; 234 | while (i-- > 0) { 235 | if (sticked[i].stickyElement.get(0) === that) { 236 | splice.call(sticked,i,1); 237 | removeIdx = i; 238 | } 239 | } 240 | if(removeIdx !== -1) { 241 | unstickyElement.unwrap(); 242 | unstickyElement 243 | .css({ 244 | 'width': '', 245 | 'position': '', 246 | 'top': '', 247 | 'float': '', 248 | 'z-index': '' 249 | }) 250 | ; 251 | } 252 | }); 253 | } 254 | }; 255 | 256 | // should be more efficient than using $window.scroll(scroller) and $window.resize(resizer): 257 | if (window.addEventListener) { 258 | window.addEventListener('scroll', scroller, false); 259 | window.addEventListener('resize', resizer, false); 260 | } else if (window.attachEvent) { 261 | window.attachEvent('onscroll', scroller); 262 | window.attachEvent('onresize', resizer); 263 | } 264 | 265 | $.fn.sticky = function(method) { 266 | if (methods[method]) { 267 | return methods[method].apply(this, slice.call(arguments, 1)); 268 | } else if (typeof method === 'object' || !method ) { 269 | return methods.init.apply( this, arguments ); 270 | } else { 271 | $.error('Method ' + method + ' does not exist on jQuery.sticky'); 272 | } 273 | }; 274 | 275 | $.fn.unstick = function(method) { 276 | if (methods[method]) { 277 | return methods[method].apply(this, slice.call(arguments, 1)); 278 | } else if (typeof method === 'object' || !method ) { 279 | return methods.unstick.apply( this, arguments ); 280 | } else { 281 | $.error('Method ' + method + ' does not exist on jQuery.sticky'); 282 | } 283 | }; 284 | $(function() { 285 | setTimeout(scroller, 0); 286 | }); 287 | })); 288 | -------------------------------------------------------------------------------- /app/assets/javascripts/sticky_map.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | $(".beds-map-wrapper").sticky({topSpacing:100}); 3 | }); 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/README.md: -------------------------------------------------------------------------------- 1 | ## Setup 2 | 3 | Ensure you have the following gems in your Rails `Gemfile` 4 | 5 | ```ruby 6 | # Gemfile 7 | gem 'bootstrap-sass' 8 | gem 'font-awesome-sass' 9 | gem 'simple_form' 10 | gem 'autoprefixer-rails' 11 | ``` 12 | 13 | In your terminal, generate SimpleForm Bootstrap config. 14 | 15 | ```bash 16 | $ bundle install 17 | $ rails generate simple_form:install --bootstrap 18 | ``` 19 | 20 | Then replace Rails' stylesheets by Le Wagon's stylesheets: 21 | 22 | ``` 23 | $ rm -rf app/assets/stylesheets 24 | $ curl -L https://github.com/lewagon/stylesheets/archive/master.zip > stylesheets.zip 25 | $ unzip stylesheets.zip -d app/assets && rm stylesheets.zip && mv app/assets/rails-stylesheets-master app/assets/stylesheets 26 | ``` 27 | 28 | Don't forget the sprockets directives in `assets/javascripts/application.js` 29 | 30 | ```javascript 31 | // app/assets/javascripts/application.js 32 | 33 | //= require jquery 34 | //= require jquery_ujs 35 | //= require bootstrap-sprockets 36 | //= require_tree . 37 | ``` 38 | 39 | And the viewport in the layout 40 | 41 | ```html 42 | 43 | 44 | 45 | 46 | 47 | 48 | ``` 49 | 50 | ## Adding new `.scss` files 51 | 52 | Look at your main `application.scss` file to see how SCSS files are imported. 53 | 54 | ```scss 55 | // Graphical variables 56 | @import "config/variables"; 57 | @import "config/bootstrap_variables"; 58 | 59 | // External libraries 60 | @import "bootstrap"; 61 | @import "font-awesome-sprockets"; 62 | @import "font-awesome"; 63 | 64 | // Your CSS 65 | @import "layout/index"; 66 | @import "components/index"; 67 | @import "pages/index"; 68 | @import "vendor/index"; 69 | ``` 70 | 71 | For every folder (**`components`**, **`layout`**, **`pages`**, **`vendor`**), there is one `_index.scss` partial which is responsible for importing all the other partials of its folder. 72 | 73 | **Example 1**: Let's say you add a new `_contact.scss` file in **`pages`** then modify `pages/_index.scss` as: 74 | 75 | ```scss 76 | // pages/_index.scss 77 | @import "home"; 78 | @import "contact"; 79 | ``` 80 | 81 | **Example 2**: Let's say you add a new `_sidebar.scss` file in **`layout`** then modify `layout/_index.scss` as: 82 | 83 | ```scss 84 | // layout/_index.scss 85 | @import "base"; 86 | @import "utilities"; 87 | @import "footer"; 88 | @import "navbar"; 89 | @import "sidebar"; 90 | ``` 91 | 92 | ## Navbar template 93 | 94 | Our `layout/_navbar.scss` code works well with our home-made ERB template which you can find 95 | 96 | - [version without login](https://github.com/lewagon/awesome-navbars/blob/master/templates/_navbar_wagon_without_login.html.erb). 97 | - [version with login](https://github.com/lewagon/awesome-navbars/blob/master/templates/_navbar_wagon.html.erb). 98 | 99 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.scss: -------------------------------------------------------------------------------- 1 | // Graphical variables 2 | @import "config/variables"; 3 | @import "config/bootstrap_variables"; 4 | 5 | // External libraries 6 | @import "bootstrap-sprockets"; 7 | @import "bootstrap"; 8 | @import "font-awesome-sprockets"; 9 | @import "font-awesome"; 10 | @import "bootstrap-datepicker"; 11 | // Your CSS 12 | @import "layout/index"; 13 | @import "components/index"; 14 | @import "pages/index"; 15 | @import "vendor/index"; 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/_alert.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------------- 2 | * Your CSS code for flash notices and alerts 3 | * ------------------------------------- */ 4 | 5 | .alert { 6 | margin: 0; 7 | text-align: center; 8 | color: white; 9 | } 10 | .alert-info { 11 | background: $green; 12 | } 13 | .alert-warning { 14 | background: $red; 15 | } 16 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/_avatars.scss: -------------------------------------------------------------------------------- 1 | .avatar { 2 | width: 55px; 3 | height: 55px; 4 | border-radius: 50%; 5 | } 6 | .avatar-large { 7 | width: 150px; 8 | height: 150px; 9 | border-radius: 50%; 10 | } 11 | 12 | .avatar-semi { 13 | width: 100px; 14 | height: 100px; 15 | border-radius: 50%; 16 | } 17 | 18 | .avatar-bordered { 19 | width: 40px; 20 | border-radius: 50%; 21 | box-shadow: 0 1px 2px rgba(0,0,0,0.2); 22 | border: white 1px solid; 23 | } 24 | .avatar-square { 25 | width: 40px; 26 | border-radius: 0px; 27 | box-shadow: 0 1px 2px rgba(0,0,0,0.2); 28 | border: white 1px solid; 29 | } 30 | 31 | .avatar-xlarge { 32 | width: 200px; 33 | height: 200px; 34 | border-radius: 50%; 35 | margin-top: 30px; 36 | margin-bottom: 10px; 37 | } 38 | .avatar-navbar { 39 | width: 50px; 40 | height: 50px; 41 | border-radius: 50%; 42 | } 43 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/_badges.scss: -------------------------------------------------------------------------------- 1 | .badge-container { 2 | position: relative; 3 | font-size: 25px; 4 | line-height: 30px; 5 | width: 30px; 6 | color: grey; 7 | } 8 | .badge { 9 | position: absolute; 10 | top: -28px; 11 | right: 11px; 12 | font-size: 10px; 13 | color: white; 14 | display: flex; 15 | align-items: center; 16 | justify-content: center; 17 | height: 18px; 18 | width: 18px; 19 | text-align: center; 20 | box-shadow: 0px 0px 2px rgba(0, 0, 0, 0.1); 21 | border-radius: 50%; 22 | } 23 | .badge-red { 24 | background: #EE5F5B; 25 | } 26 | .badge-green { 27 | background: #32B796; 28 | } 29 | .badge-blue { 30 | background: #469AE0; 31 | } 32 | .badge-black { 33 | background: black; 34 | } 35 | .badge-bordered { 36 | box-shadow: 0 1px 2px rgba(0,0,0,0.2); 37 | border: white 1px solid; 38 | } 39 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/_button.scss: -------------------------------------------------------------------------------- 1 | .btn-medium { 2 | color: black; 3 | border: 2px solid black; 4 | padding: 10px 15px; 5 | border-radius: 50px; 6 | font-weight: lighter; 7 | opacity: 0.6; 8 | } 9 | 10 | .icon-validate { 11 | font-size: 40px; 12 | } 13 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/_cards.scss: -------------------------------------------------------------------------------- 1 | .card { 2 | height: 65px; 3 | background-size: cover !important; 4 | color: black; 5 | position: relative; 6 | border-radius: 5px; 7 | margin-bottom: 20px; 8 | } 9 | 10 | 11 | 12 | .showmaincard { 13 | height: 300px; 14 | margin-top: 20px; 15 | } 16 | 17 | .usercardtext { 18 | width : 50px; 19 | } 20 | 21 | .card-image { 22 | height: 175px; 23 | background-size: cover !important; 24 | position: relative; 25 | text-shadow: 0 1px 3px rgba(0,0,0,0.6); 26 | color: white; 27 | border-top-left-radius: 4px; 28 | border-top-right-radius: 4px; 29 | image-position: center; 30 | background-position: center; 31 | 32 | } 33 | .card-user { 34 | position: absolute; 35 | right: 10px; 36 | top: 10px; 37 | } 38 | .card-first-name { 39 | position: absolute; 40 | top: 10px; 41 | left: 10px; 42 | font-size: 15px; 43 | text-transform: uppercase; 44 | } 45 | .card-description { 46 | position: absolute; 47 | top: 10px; 48 | left: 10px; 49 | padding-bottom: 10px; 50 | } 51 | .card-description h2 { 52 | font-size: 20px; 53 | } 54 | .card-description p { 55 | font-size: 13px; 56 | } 57 | 58 | .card-price { 59 | position: absolute; 60 | top: 10px; 61 | right: 10px; 62 | color: black; 63 | } 64 | 65 | #city { 66 | color: #EC605F; 67 | } 68 | 69 | .card-price h2{ 70 | font-size: 20px; 71 | margin-top: 10px; 72 | } 73 | 74 | .cardContainer { 75 | box-shadow: 2px 4px 5px #E8F1F5; 76 | border-radius: 4px; 77 | } 78 | 79 | .cardContainer:hover{ 80 | opacity: 0.5; 81 | } 82 | 83 | 84 | .wagoncard { 85 | height: 300px; 86 | 87 | background-size: cover !important; 88 | color: #999999; 89 | position: relative; 90 | border-top: 1px solid #DBDBDB; 91 | border-bottom: 1px solid #DBDBDB; 92 | border-radius: 4px 93 | } 94 | .wagoncard-user { 95 | position: absolute; 96 | right: 10px; 97 | top: 10px; 98 | } 99 | .wagoncard-category { 100 | position: absolute; 101 | top: 10px; 102 | left: 15px; 103 | font-size: 20px; 104 | text-transform: uppercase; 105 | } 106 | .wagoncard-description { 107 | position: absolute; 108 | bottom: 10px; 109 | left: 15px; 110 | } 111 | 112 | .wagoncard-detail { 113 | position: absolute; 114 | top: 50px; 115 | left: 15px; 116 | width: 300px; 117 | } 118 | 119 | 120 | .wagoncard-description h2 { 121 | font-size: 24px; 122 | } 123 | // .wagoncard-description p { 124 | // font-size: 13px; 125 | // } 126 | .wagoncard-link { 127 | position: absolute; 128 | top: 0; 129 | bottom: 0; 130 | right: 0; 131 | width: 100%; 132 | z-index:2; 133 | background: black; 134 | opacity: 0; 135 | } 136 | .wagoncard-link:hover{ 137 | opacity: 0.1; 138 | } 139 | 140 | .wagoncard-listing-description{ 141 | position: absolute; 142 | bottom: 10px; 143 | left: 15px; 144 | } 145 | 146 | 147 | .booking-card { 148 | border: 2px solid black; 149 | padding: 20px; 150 | border-radius: 10px; 151 | } 152 | 153 | .review-chat { 154 | display: flex; 155 | } 156 | 157 | .review-comment { 158 | margin-left: 30px; 159 | } 160 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/_form.scss: -------------------------------------------------------------------------------- 1 | .attachinary_container li{ 2 | list-style: none 3 | } 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/_images.scss: -------------------------------------------------------------------------------- 1 | .equipment { 2 | width : 25px; 3 | } 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/_index.scss: -------------------------------------------------------------------------------- 1 | @import "alert"; 2 | @import "avatars"; 3 | @import "badges"; 4 | @import "cards"; 5 | @import "staticmap"; 6 | @import "images"; 7 | @import "button"; 8 | @import "form"; 9 | -------------------------------------------------------------------------------- /app/assets/stylesheets/components/_staticmap.scss: -------------------------------------------------------------------------------- 1 | #static-map { 2 | display: flex; 3 | height: 100vh; 4 | width: 100%; 5 | } 6 | 7 | 8 | // #map { 9 | // margin-right: 60px; 10 | 11 | // } 12 | -------------------------------------------------------------------------------- /app/assets/stylesheets/config/_bootstrap_variables.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------------- 2 | * Bootstrap sass variable 3 | * (see http://getbootstrap.com/customize/#less-variables) 4 | * ------------------------------------- */ 5 | 6 | // General style 7 | $font-family-sans-serif: $base-font; 8 | $body-bg: white; 9 | $font-size-base: $base-size; 10 | $line-height-base: $base-height; 11 | $headings-font-family: $header-font; 12 | 13 | // Semantic color scheme 14 | // => http://getbootstrap.com/customize/#colors 15 | $gray-base: $gray; 16 | $brand-primary: $blue; 17 | $brand-success: $green; 18 | $brand-info: $yellow; 19 | $brand-danger: $red; 20 | $brand-warning: $orange; 21 | 22 | // Buttons / inputs radius 23 | $border-radius-base: 2px; 24 | $border-radius-large: 2px; 25 | $border-radius-small: 2px; -------------------------------------------------------------------------------- /app/assets/stylesheets/config/_variables.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------------- 2 | * Fonts 3 | * ------------------------------------- */ 4 | // Google fonts 5 | @import url("https://fonts.googleapis.com/css?family=Open+Sans:400,300,700|Raleway:400,100,300,700,500"); 6 | $base-font: "Open Sans", "Helvetica", "sans-serif"; 7 | $header-font: "Raleway", "Helvetica", "sans-serif"; 8 | 9 | // Local fonts (uncomment following lines) 10 | // @font-face { 11 | // font-family: "Font Name"; 12 | // src: font-url('FontFile.eot'); 13 | // src: font-url('FontFile.eot?#iefix') format('embedded-opentype'), 14 | // font-url('FontFile.woff') format('woff'), 15 | // font-url('FontFile.ttf') format('truetype') 16 | // } 17 | // $my-font: "Font Name"; 18 | 19 | // Font-size and line-height 20 | $base-size: 16px; 21 | $base-height: 1.4; 22 | 23 | /* ------------------------------------- 24 | * Colors 25 | * ------------------------------------- */ 26 | // Scheme 27 | $brand-color: #D23333; 28 | 29 | $red: #EE5F5B; 30 | $blue: #469AE0; 31 | $yellow: #FDB631; 32 | $orange: #E67E22; 33 | $green: #32B796; 34 | $gray: #000000; 35 | -------------------------------------------------------------------------------- /app/assets/stylesheets/layout/_footer.scss: -------------------------------------------------------------------------------- 1 | #footer { 2 | background: #F5F5F5; 3 | padding: 8px 0; 4 | color: #FFFFFF; 5 | margin-top: 35px; 6 | } 7 | 8 | .container { 9 | width: 1170px; 10 | } 11 | 12 | 13 | #footer ul { 14 | margin-top: 10px; 15 | } 16 | 17 | .list-inline { 18 | padding-left: 0; 19 | margin-left: -5px; 20 | list-style: none; 21 | } 22 | 23 | #footer p { 24 | margin-top: 17px; 25 | } 26 | 27 | #footer a { 28 | color: grey; 29 | letter-spacing: 20px; 30 | transition: color 0.5s ease; 31 | } 32 | 33 | #footer a:hover { 34 | color: #333333; 35 | } 36 | 37 | p { 38 | margin: 0 0 10px; 39 | } 40 | -------------------------------------------------------------------------------- /app/assets/stylesheets/layout/_index.scss: -------------------------------------------------------------------------------- 1 | @import "utilities"; 2 | @import "footer"; 3 | @import "navbar"; 4 | -------------------------------------------------------------------------------- /app/assets/stylesheets/layout/_navbar.scss: -------------------------------------------------------------------------------- 1 | /* Main class */ 2 | .navbar-wagon { 3 | box-shadow: 0 1px 5px 0 rgba(0,0,0,0.07),0 1px 0 0 rgba(0,0,0,0.03); 4 | background: white; 5 | transition: all 0.3s ease; 6 | display: flex; 7 | height: 70px; 8 | padding: 0px 30px; 9 | align-items: center; 10 | justify-content: space-between; 11 | } 12 | 13 | /* Optional class to fix the navbar on top */ 14 | .navbar-wagon-fixed { 15 | position: fixed; 16 | left: 0px; 17 | top: 0px; 18 | z-index: 1; 19 | width: 100%; 20 | } 21 | 22 | /* Navbar logo */ 23 | .navbar-wagon-brand img { 24 | width: 50px; 25 | } 26 | 27 | /* Navbar right section (with form, links, button) */ 28 | .navbar-wagon-right { 29 | display: flex; 30 | align-items: center; 31 | justify-content: space-between; 32 | } 33 | 34 | /* Navbar item */ 35 | .navbar-wagon-item { 36 | flex: 0 1 auto; 37 | cursor: pointer; 38 | padding: 0 20px; 39 | } 40 | 41 | /* Navbar standard link */ 42 | .navbar-wagon-link { 43 | color: #616668; 44 | font-size: 18px; 45 | text-decoration: none; 46 | } 47 | .navbar-wagon-link:hover { 48 | color: #da552f; 49 | text-decoration: none; 50 | } 51 | 52 | /* Navbar right button */ 53 | .navbar-wagon-button { 54 | margin-left: 10px; 55 | padding: 0 20px; 56 | border-radius: 20em; 57 | line-height: 40px; 58 | background-color: #D23333; 59 | color: white; 60 | font-size: 14px; 61 | border: 2px solid #D23333; 62 | } 63 | .navbar-wagon-button:hover { 64 | color: white; 65 | background: #D23333; 66 | border-color: #ac2626; 67 | text-decoration: none; 68 | } 69 | 70 | /* Navbar search form */ 71 | .navbar-wagon-search { 72 | flex: 0 1 300px; 73 | display: flex; 74 | justify-content: flex-end; 75 | padding: 0 10px; 76 | position: relative; 77 | } 78 | .navbar-wagon-search-btn { 79 | line-height: 40px; 80 | color: #E6E6E6; 81 | border: none; 82 | background: transparent; 83 | position: absolute; 84 | right: 14px; 85 | top: -2px; 86 | z-index: 1; 87 | } 88 | .navbar-wagon-search-input { 89 | flex: 0 1 300px; 90 | transition: all 0.15s ease; 91 | line-height: 40px; 92 | font-weight: lighter; 93 | color: #666666; 94 | border: 1px solid #E6E6E6; 95 | border-radius: 5px; 96 | padding: 0 10px; 97 | font-size: 14px; 98 | outline: none; 99 | } 100 | .navbar-wagon-search-input:focus { 101 | border: 1px solid #CCCCCC; 102 | } 103 | 104 | /* Navbar dropdown menu */ 105 | .navbar-wagon-dropdown-menu { 106 | margin-top: 15px; 107 | box-shadow: 1px 1px 4px #E6E6E6; 108 | border-color: #E6E6E6; 109 | } 110 | .navbar-wagon-dropdown-menu li > a { 111 | transition: color 0.3s ease; 112 | font-weight: lighter !important; 113 | color: #999999 !important; 114 | font-size: 15px !important; 115 | line-height: 22px !important; 116 | padding: 10px 20px; 117 | } 118 | .navbar-wagon-dropdown-menu li > a:hover { 119 | background: transparent !important; 120 | color: black !important; 121 | text-decoration: none; 122 | } 123 | .navbar-wagon-dropdown-menu:before { 124 | content: ' '; 125 | height: 10px; 126 | width: 10px; 127 | position: absolute; 128 | right: 10px; 129 | top: -6px; 130 | background-color: white; 131 | transform: rotate(45deg); 132 | border-left: 1px solid #E6E6E6; 133 | border-top: 1px solid #E6E6E6; 134 | } 135 | -------------------------------------------------------------------------------- /app/assets/stylesheets/layout/_utilities.scss: -------------------------------------------------------------------------------- 1 | /* ------------------------------------- 2 | * Utilities classes 3 | * These are examples of utilities classes 4 | * Feel free to change them and create your own 5 | * ------------------------------------- */ 6 | 7 | // Paddings 8 | .padded { 9 | padding-top: 3em; 10 | padding-bottom: 5em; 11 | } 12 | 13 | // Backgrounds 14 | .bg-black { 15 | background: #4a4a4a; 16 | } 17 | .bg-grey { 18 | background: #aeaeae; 19 | } 20 | .bg-blue { 21 | background: #00a3e1; 22 | } 23 | .bg-dark-blue { 24 | background: #3b5998; 25 | } 26 | 27 | 28 | .page-content { 29 | min-height: 90vh; 30 | } 31 | 32 | body { padding-top: 70px; 33 | 34 | } 35 | 36 | .td { 37 | padding: 8px; 38 | } 39 | -------------------------------------------------------------------------------- /app/assets/stylesheets/pages/_bed_show.scss: -------------------------------------------------------------------------------- 1 | 2 | @media (min-width: 1200px) { 3 | .container{ 4 | max-width: 970px; 5 | } 6 | } 7 | 8 | .photo-row { 9 | height: 350px; 10 | width : 100%; 11 | border-bottom: 1px solid #DBDBDB; 12 | margin-bottom: 20px; 13 | } 14 | 15 | .equipment-div { 16 | 17 | width : 100%; 18 | border-top: 1px solid #DBDBDB; 19 | border-bottom: 1px solid #DBDBDB; 20 | margin-bottom: 20px; 21 | padding-top : 10px; 22 | padding-bottom : 10px; 23 | } 24 | 25 | .pad{ 26 | margin-right: 20px; 27 | } 28 | 29 | .card-image { 30 | height: 175px; 31 | background-size: cover !important; 32 | position: relative; 33 | text-shadow: 0 1px 3px rgba(0,0,0,0.6); 34 | color: white; 35 | border-top-left-radius: 4px; 36 | border-top-right-radius: 4px; 37 | image-position: center; 38 | background-position: center; 39 | } 40 | 41 | .bookContainer { 42 | margin-top: 10px; 43 | margin-bottom: 10px; 44 | box-shadow: 2px 4px 5px #E8F1F5; 45 | border-radius: 4px; 46 | } 47 | 48 | .DescriptionBedContainer { 49 | margin-top: 10px; 50 | margin-bottom: 10px; 51 | box-shadow: 2px 4px 5px #E8F1F5; 52 | border-radius: 4px; 53 | } 54 | 55 | .profilContainer { 56 | margin-top: 10px; 57 | margin-bottom: 10px; 58 | box-shadow: 2px 4px 5px #EC605F; 59 | border-radius: 4px; 60 | // border-color: #EC605F; 61 | position: relative; 62 | height: 300px; 63 | // background-color: #F6F6F6; 64 | } 65 | 66 | .PhotoBedContainer{ 67 | margin-top: 10px; 68 | margin-bottom: 10px; 69 | box-shadow: 2px 4px 5px #E8F1F5; 70 | border-radius: 4px; 71 | } 72 | 73 | .photoProfil{ 74 | position: absolute; 75 | right: 30px; 76 | top: 75px; 77 | } 78 | 79 | .profilDescription{ 80 | position: absolute; 81 | left: 20px; 82 | top: 40px; 83 | padding-left: 10px; 84 | } 85 | 86 | 87 | -------------------------------------------------------------------------------- /app/assets/stylesheets/pages/_beds_form.scss: -------------------------------------------------------------------------------- 1 | #wrapper { 2 | justify-content : space-around; 3 | margin-bottom: 20px; 4 | width: 50%; 5 | margin: 0 auto; 6 | } 7 | 8 | #wrapper h3 { 9 | font-family: 'Questrial', sans-serif; 10 | color: #FF494A; 11 | } 12 | 13 | .form-login { 14 | padding: 10px 10px; 15 | border-radius: 3px; 16 | margin: 30px; 17 | background-color: rgb(250, 250, 250) ; 18 | } 19 | -------------------------------------------------------------------------------- /app/assets/stylesheets/pages/_beds_index.scss: -------------------------------------------------------------------------------- 1 | .containerIndex { 2 | margin-top: 20px; 3 | } 4 | 5 | #title-index { 6 | color: #EC605F; 7 | } 8 | -------------------------------------------------------------------------------- /app/assets/stylesheets/pages/_edit_bed.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | width: 1170px; 3 | } 4 | 5 | .form-login { 6 | border-radius: 3px; 7 | } 8 | 9 | #red-word { 10 | color: #FF494A; 11 | } 12 | -------------------------------------------------------------------------------- /app/assets/stylesheets/pages/_home.scss: -------------------------------------------------------------------------------- 1 | 2 | .banner { 3 | color: white; 4 | text-align: center; 5 | height: 80vh; 6 | background-size: cover !important; 7 | display: flex; 8 | align-items: center; 9 | justify-content: center; 10 | margin-bottom: 30px; 11 | } 12 | .banner h1 { 13 | font-size: 50px; 14 | font-weight: bold; 15 | text-shadow: 0px 1px rgba(0, 0, 0, 0.2); 16 | } 17 | .banner p { 18 | font-size: 24px; 19 | font-weight: lighter; 20 | color: white; 21 | margin-bottom: 20px; 22 | } 23 | 24 | .btn { 25 | border-radius: 10px; 26 | } 27 | 28 | .border-radius { 29 | border-radius: 10px; 30 | } 31 | 32 | .title-index-padding { 33 | padding-bottom: 30px; 34 | } 35 | -------------------------------------------------------------------------------- /app/assets/stylesheets/pages/_index.scss: -------------------------------------------------------------------------------- 1 | @import "home"; 2 | @import "beds_form"; 3 | @import "bed_show"; 4 | @import "beds_index"; 5 | @import "login"; 6 | @import "signup"; 7 | @import "edit_bed"; 8 | @import "my_booking"; 9 | 10 | 11 | -------------------------------------------------------------------------------- /app/assets/stylesheets/pages/_login.scss: -------------------------------------------------------------------------------- 1 | .container{ 2 | width: 1170px; 3 | padding-top: 30px; 4 | background-size: cover !important; 5 | } 6 | 7 | .form { 8 | border-radius: 3px; 9 | padding-right: 50px; 10 | padding-left: 50px; 11 | background-color: white; 12 | border: 0.1px solid #E6E6E6; 13 | margin-right: 10px; 14 | margin-left: 100px; 15 | margin-top: 70px; 16 | } 17 | 18 | .form h2 { 19 | font-weight: bold; 20 | color: #4C4C4C; 21 | } 22 | 23 | -------------------------------------------------------------------------------- /app/assets/stylesheets/pages/_my_booking.scss: -------------------------------------------------------------------------------- 1 | .wrapper-dashboard { 2 | width: 75%; 3 | justify-content: text-center; 4 | margin: 0 auto; 5 | } 6 | 7 | .dashboard { 8 | display: flex; 9 | align-items: center; 10 | padding: 20px; 11 | border-radius: 3px; 12 | transition: all 0.15s ease; 13 | } 14 | 15 | /* Body design */ 16 | .product-body { 17 | flex: 1 1 auto; 18 | } 19 | .product-body h3 { 20 | font-weight: bold; 21 | font-size: 23px; 22 | margin-top: 0; 23 | font-family: 'Kalam', cursive; 24 | } 25 | .product-body p { 26 | font-weight: lighter; 27 | color: #4C4C4C; 28 | margin-bottom: 0; 29 | } 30 | 31 | /* Product image */ 32 | .product-image { 33 | border-radius: 10px; 34 | margin-right: 20px; 35 | width: 175px; 36 | height: 145px; 37 | } 38 | 39 | /* Controls design */ 40 | .product-controls { 41 | display: flex; 42 | align-items: center; 43 | text-align: center; 44 | margin: 0px; 45 | } 46 | .product-controls a { 47 | padding: 0 20px; 48 | font-size: 17px; 49 | color: #E6E6E6; 50 | } 51 | .product-controls a:hover { 52 | color: #D3473C !important 53 | } 54 | .product-controls-hidden a { 55 | color: transparent; 56 | font-size: 15px; 57 | transition: all 0.15s ease; 58 | border-color: transparent; 59 | } 60 | 61 | /* Hover effects */ 62 | .dashboard:hover { 63 | background: #f7f7fa; 64 | cursor: pointer; 65 | } 66 | 67 | // .product:hover .product-upvote { transform: scale(1.2) } 68 | .dashboard:hover .product-controls-hidden a { color: #E6E6E6 } 69 | .product-upvote:hover .product-arrow { border-bottom: 9px solid #5898f1 } 70 | 71 | 72 | .congrat-text { 73 | font-weight: bolder; 74 | font-family: 'Kalam', cursive; 75 | } 76 | 77 | .pdt-image { 78 | border-radius: 10px; 79 | margin-right: 20px; 80 | width: 270px; 81 | height: 215px; 82 | } 83 | 84 | .btn-default-black { 85 | color: #4C4C4C; 86 | 87 | } 88 | 89 | 90 | .btn-default-black:hover { 91 | color: white; 92 | 93 | } 94 | 95 | .product-body h4 { 96 | font-size: 17px; 97 | color: #4C4C4C; 98 | margin-bottom: 20px; 99 | margin-left: 20px; 100 | } 101 | 102 | .product-body h2 { 103 | font-weight: bold; 104 | font-size: 27px; 105 | margin-top: 2px; 106 | font-family: 'Kalam', cursive; 107 | margin-bottom: 50px; 108 | margin-left: 18px; 109 | } 110 | 111 | .review-coment { 112 | padding-right: 82px; 113 | } 114 | 115 | .review { 116 | background-color: #FFFFFF; 117 | padding: 20px; 118 | } 119 | -------------------------------------------------------------------------------- /app/assets/stylesheets/pages/_signup.scss: -------------------------------------------------------------------------------- 1 | .container { 2 | width: 1170px; 3 | padding-top: 40px; 4 | padding-bottom: 90px; 5 | } 6 | 7 | .form { 8 | border-radius: 3px; 9 | padding-right: 50px; 10 | padding-left: 50px; 11 | background-color: white; 12 | padding-bottom: 30px; 13 | } 14 | 15 | .form h2 { 16 | font-weight: bold; 17 | color: #4C4C4C; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /app/assets/stylesheets/vendor/_animation_cheat_sheet.scss: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================== 3 | CSS3 ANIMATION CHEAT SHEET 4 | ============================================== 5 | 6 | Made by Justin Aguilar 7 | 8 | www.justinaguilar.com/animations/ 9 | 10 | Questions, comments, concerns, love letters: 11 | justin@justinaguilar.com 12 | ============================================== 13 | */ 14 | 15 | /* 16 | ============================================== 17 | slideDown 18 | ============================================== 19 | */ 20 | 21 | 22 | .slideDown{ 23 | animation-name: slideDown; 24 | -webkit-animation-name: slideDown; 25 | 26 | animation-duration: 1s; 27 | -webkit-animation-duration: 1s; 28 | 29 | animation-timing-function: ease; 30 | -webkit-animation-timing-function: ease; 31 | 32 | visibility: visible !important; 33 | } 34 | 35 | @keyframes slideDown { 36 | 0% { 37 | transform: translateY(-100%); 38 | } 39 | 50%{ 40 | transform: translateY(8%); 41 | } 42 | 65%{ 43 | transform: translateY(-4%); 44 | } 45 | 80%{ 46 | transform: translateY(4%); 47 | } 48 | 95%{ 49 | transform: translateY(-2%); 50 | } 51 | 100% { 52 | transform: translateY(0%); 53 | } 54 | } 55 | 56 | @-webkit-keyframes slideDown { 57 | 0% { 58 | -webkit-transform: translateY(-100%); 59 | } 60 | 50%{ 61 | -webkit-transform: translateY(8%); 62 | } 63 | 65%{ 64 | -webkit-transform: translateY(-4%); 65 | } 66 | 80%{ 67 | -webkit-transform: translateY(4%); 68 | } 69 | 95%{ 70 | -webkit-transform: translateY(-2%); 71 | } 72 | 100% { 73 | -webkit-transform: translateY(0%); 74 | } 75 | } 76 | 77 | /* 78 | ============================================== 79 | slideUp 80 | ============================================== 81 | */ 82 | 83 | 84 | .slideUp{ 85 | animation-name: slideUp; 86 | -webkit-animation-name: slideUp; 87 | 88 | animation-duration: 1s; 89 | -webkit-animation-duration: 1s; 90 | 91 | animation-timing-function: ease; 92 | -webkit-animation-timing-function: ease; 93 | 94 | visibility: visible !important; 95 | } 96 | 97 | @keyframes slideUp { 98 | 0% { 99 | transform: translateY(100%); 100 | } 101 | 50%{ 102 | transform: translateY(-8%); 103 | } 104 | 65%{ 105 | transform: translateY(4%); 106 | } 107 | 80%{ 108 | transform: translateY(-4%); 109 | } 110 | 95%{ 111 | transform: translateY(2%); 112 | } 113 | 100% { 114 | transform: translateY(0%); 115 | } 116 | } 117 | 118 | @-webkit-keyframes slideUp { 119 | 0% { 120 | -webkit-transform: translateY(100%); 121 | } 122 | 50%{ 123 | -webkit-transform: translateY(-8%); 124 | } 125 | 65%{ 126 | -webkit-transform: translateY(4%); 127 | } 128 | 80%{ 129 | -webkit-transform: translateY(-4%); 130 | } 131 | 95%{ 132 | -webkit-transform: translateY(2%); 133 | } 134 | 100% { 135 | -webkit-transform: translateY(0%); 136 | } 137 | } 138 | 139 | /* 140 | ============================================== 141 | slideLeft 142 | ============================================== 143 | */ 144 | 145 | 146 | .slideLeft{ 147 | animation-name: slideLeft; 148 | -webkit-animation-name: slideLeft; 149 | 150 | animation-duration: 1s; 151 | -webkit-animation-duration: 1s; 152 | 153 | animation-timing-function: ease-in-out; 154 | -webkit-animation-timing-function: ease-in-out; 155 | 156 | visibility: visible !important; 157 | } 158 | 159 | @keyframes slideLeft { 160 | 0% { 161 | transform: translateX(150%); 162 | } 163 | 50%{ 164 | transform: translateX(-8%); 165 | } 166 | 65%{ 167 | transform: translateX(4%); 168 | } 169 | 80%{ 170 | transform: translateX(-4%); 171 | } 172 | 95%{ 173 | transform: translateX(2%); 174 | } 175 | 100% { 176 | transform: translateX(0%); 177 | } 178 | } 179 | 180 | @-webkit-keyframes slideLeft { 181 | 0% { 182 | -webkit-transform: translateX(150%); 183 | } 184 | 50%{ 185 | -webkit-transform: translateX(-8%); 186 | } 187 | 65%{ 188 | -webkit-transform: translateX(4%); 189 | } 190 | 80%{ 191 | -webkit-transform: translateX(-4%); 192 | } 193 | 95%{ 194 | -webkit-transform: translateX(2%); 195 | } 196 | 100% { 197 | -webkit-transform: translateX(0%); 198 | } 199 | } 200 | 201 | /* 202 | ============================================== 203 | slideRight 204 | ============================================== 205 | */ 206 | 207 | 208 | .slideRight{ 209 | animation-name: slideRight; 210 | -webkit-animation-name: slideRight; 211 | 212 | animation-duration: 1s; 213 | -webkit-animation-duration: 1s; 214 | 215 | animation-timing-function: ease-in-out; 216 | -webkit-animation-timing-function: ease-in-out; 217 | 218 | visibility: visible !important; 219 | } 220 | 221 | @keyframes slideRight { 222 | 0% { 223 | transform: translateX(-150%); 224 | } 225 | 50%{ 226 | transform: translateX(8%); 227 | } 228 | 65%{ 229 | transform: translateX(-4%); 230 | } 231 | 80%{ 232 | transform: translateX(4%); 233 | } 234 | 95%{ 235 | transform: translateX(-2%); 236 | } 237 | 100% { 238 | transform: translateX(0%); 239 | } 240 | } 241 | 242 | @-webkit-keyframes slideRight { 243 | 0% { 244 | -webkit-transform: translateX(-150%); 245 | } 246 | 50%{ 247 | -webkit-transform: translateX(8%); 248 | } 249 | 65%{ 250 | -webkit-transform: translateX(-4%); 251 | } 252 | 80%{ 253 | -webkit-transform: translateX(4%); 254 | } 255 | 95%{ 256 | -webkit-transform: translateX(-2%); 257 | } 258 | 100% { 259 | -webkit-transform: translateX(0%); 260 | } 261 | } 262 | 263 | /* 264 | ============================================== 265 | slideExpandUp 266 | ============================================== 267 | */ 268 | 269 | 270 | .slideExpandUp{ 271 | animation-name: slideExpandUp; 272 | -webkit-animation-name: slideExpandUp; 273 | 274 | animation-duration: 1.6s; 275 | -webkit-animation-duration: 1.6s; 276 | 277 | animation-timing-function: ease-out; 278 | -webkit-animation-timing-function: ease -out; 279 | 280 | visibility: visible !important; 281 | } 282 | 283 | @keyframes slideExpandUp { 284 | 0% { 285 | transform: translateY(100%) scaleX(0.5); 286 | } 287 | 30%{ 288 | transform: translateY(-8%) scaleX(0.5); 289 | } 290 | 40%{ 291 | transform: translateY(2%) scaleX(0.5); 292 | } 293 | 50%{ 294 | transform: translateY(0%) scaleX(1.1); 295 | } 296 | 60%{ 297 | transform: translateY(0%) scaleX(0.9); 298 | } 299 | 70% { 300 | transform: translateY(0%) scaleX(1.05); 301 | } 302 | 80%{ 303 | transform: translateY(0%) scaleX(0.95); 304 | } 305 | 90% { 306 | transform: translateY(0%) scaleX(1.02); 307 | } 308 | 100%{ 309 | transform: translateY(0%) scaleX(1); 310 | } 311 | } 312 | 313 | @-webkit-keyframes slideExpandUp { 314 | 0% { 315 | -webkit-transform: translateY(100%) scaleX(0.5); 316 | } 317 | 30%{ 318 | -webkit-transform: translateY(-8%) scaleX(0.5); 319 | } 320 | 40%{ 321 | -webkit-transform: translateY(2%) scaleX(0.5); 322 | } 323 | 50%{ 324 | -webkit-transform: translateY(0%) scaleX(1.1); 325 | } 326 | 60%{ 327 | -webkit-transform: translateY(0%) scaleX(0.9); 328 | } 329 | 70% { 330 | -webkit-transform: translateY(0%) scaleX(1.05); 331 | } 332 | 80%{ 333 | -webkit-transform: translateY(0%) scaleX(0.95); 334 | } 335 | 90% { 336 | -webkit-transform: translateY(0%) scaleX(1.02); 337 | } 338 | 100%{ 339 | -webkit-transform: translateY(0%) scaleX(1); 340 | } 341 | } 342 | 343 | /* 344 | ============================================== 345 | expandUp 346 | ============================================== 347 | */ 348 | 349 | 350 | .expandUp{ 351 | animation-name: expandUp; 352 | -webkit-animation-name: expandUp; 353 | 354 | animation-duration: 0.7s; 355 | -webkit-animation-duration: 0.7s; 356 | 357 | animation-timing-function: ease; 358 | -webkit-animation-timing-function: ease; 359 | 360 | visibility: visible !important; 361 | } 362 | 363 | @keyframes expandUp { 364 | 0% { 365 | transform: translateY(100%) scale(0.6) scaleY(0.5); 366 | } 367 | 60%{ 368 | transform: translateY(-7%) scaleY(1.12); 369 | } 370 | 75%{ 371 | transform: translateY(3%); 372 | } 373 | 100% { 374 | transform: translateY(0%) scale(1) scaleY(1); 375 | } 376 | } 377 | 378 | @-webkit-keyframes expandUp { 379 | 0% { 380 | -webkit-transform: translateY(100%) scale(0.6) scaleY(0.5); 381 | } 382 | 60%{ 383 | -webkit-transform: translateY(-7%) scaleY(1.12); 384 | } 385 | 75%{ 386 | -webkit-transform: translateY(3%); 387 | } 388 | 100% { 389 | -webkit-transform: translateY(0%) scale(1) scaleY(1); 390 | } 391 | } 392 | 393 | /* 394 | ============================================== 395 | fadeIn 396 | ============================================== 397 | */ 398 | 399 | .fadeIn{ 400 | animation-name: fadeIn; 401 | -webkit-animation-name: fadeIn; 402 | 403 | animation-duration: 1.5s; 404 | -webkit-animation-duration: 1.5s; 405 | 406 | animation-timing-function: ease-in-out; 407 | -webkit-animation-timing-function: ease-in-out; 408 | 409 | visibility: visible !important; 410 | } 411 | 412 | @keyframes fadeIn { 413 | 0% { 414 | transform: scale(0); 415 | opacity: 0.0; 416 | } 417 | 60% { 418 | transform: scale(1.1); 419 | } 420 | 80% { 421 | transform: scale(0.9); 422 | opacity: 1; 423 | } 424 | 100% { 425 | transform: scale(1); 426 | opacity: 1; 427 | } 428 | } 429 | 430 | @-webkit-keyframes fadeIn { 431 | 0% { 432 | -webkit-transform: scale(0); 433 | opacity: 0.0; 434 | } 435 | 60% { 436 | -webkit-transform: scale(1.1); 437 | } 438 | 80% { 439 | -webkit-transform: scale(0.9); 440 | opacity: 1; 441 | } 442 | 100% { 443 | -webkit-transform: scale(1); 444 | opacity: 1; 445 | } 446 | } 447 | 448 | /* 449 | ============================================== 450 | expandOpen 451 | ============================================== 452 | */ 453 | 454 | 455 | .expandOpen{ 456 | animation-name: expandOpen; 457 | -webkit-animation-name: expandOpen; 458 | 459 | animation-duration: 1.2s; 460 | -webkit-animation-duration: 1.2s; 461 | 462 | animation-timing-function: ease-out; 463 | -webkit-animation-timing-function: ease-out; 464 | 465 | visibility: visible !important; 466 | } 467 | 468 | @keyframes expandOpen { 469 | 0% { 470 | transform: scale(1.8); 471 | } 472 | 50% { 473 | transform: scale(0.95); 474 | } 475 | 80% { 476 | transform: scale(1.05); 477 | } 478 | 90% { 479 | transform: scale(0.98); 480 | } 481 | 100% { 482 | transform: scale(1); 483 | } 484 | } 485 | 486 | @-webkit-keyframes expandOpen { 487 | 0% { 488 | -webkit-transform: scale(1.8); 489 | } 490 | 50% { 491 | -webkit-transform: scale(0.95); 492 | } 493 | 80% { 494 | -webkit-transform: scale(1.05); 495 | } 496 | 90% { 497 | -webkit-transform: scale(0.98); 498 | } 499 | 100% { 500 | -webkit-transform: scale(1); 501 | } 502 | } 503 | 504 | /* 505 | ============================================== 506 | bigEntrance 507 | ============================================== 508 | */ 509 | 510 | 511 | .bigEntrance{ 512 | animation-name: bigEntrance; 513 | -webkit-animation-name: bigEntrance; 514 | 515 | animation-duration: 1.6s; 516 | -webkit-animation-duration: 1.6s; 517 | 518 | animation-timing-function: ease-out; 519 | -webkit-animation-timing-function: ease-out; 520 | 521 | visibility: visible !important; 522 | } 523 | 524 | @keyframes bigEntrance { 525 | 0% { 526 | transform: scale(0.3) rotate(6deg) translateX(-30%) translateY(30%); 527 | opacity: 0.2; 528 | } 529 | 30% { 530 | transform: scale(1.03) rotate(-2deg) translateX(2%) translateY(-2%); 531 | opacity: 1; 532 | } 533 | 45% { 534 | transform: scale(0.98) rotate(1deg) translateX(0%) translateY(0%); 535 | opacity: 1; 536 | } 537 | 60% { 538 | transform: scale(1.01) rotate(-1deg) translateX(0%) translateY(0%); 539 | opacity: 1; 540 | } 541 | 75% { 542 | transform: scale(0.99) rotate(1deg) translateX(0%) translateY(0%); 543 | opacity: 1; 544 | } 545 | 90% { 546 | transform: scale(1.01) rotate(0deg) translateX(0%) translateY(0%); 547 | opacity: 1; 548 | } 549 | 100% { 550 | transform: scale(1) rotate(0deg) translateX(0%) translateY(0%); 551 | opacity: 1; 552 | } 553 | } 554 | 555 | @-webkit-keyframes bigEntrance { 556 | 0% { 557 | -webkit-transform: scale(0.3) rotate(6deg) translateX(-30%) translateY(30%); 558 | opacity: 0.2; 559 | } 560 | 30% { 561 | -webkit-transform: scale(1.03) rotate(-2deg) translateX(2%) translateY(-2%); 562 | opacity: 1; 563 | } 564 | 45% { 565 | -webkit-transform: scale(0.98) rotate(1deg) translateX(0%) translateY(0%); 566 | opacity: 1; 567 | } 568 | 60% { 569 | -webkit-transform: scale(1.01) rotate(-1deg) translateX(0%) translateY(0%); 570 | opacity: 1; 571 | } 572 | 75% { 573 | -webkit-transform: scale(0.99) rotate(1deg) translateX(0%) translateY(0%); 574 | opacity: 1; 575 | } 576 | 90% { 577 | -webkit-transform: scale(1.01) rotate(0deg) translateX(0%) translateY(0%); 578 | opacity: 1; 579 | } 580 | 100% { 581 | -webkit-transform: scale(1) rotate(0deg) translateX(0%) translateY(0%); 582 | opacity: 1; 583 | } 584 | } 585 | 586 | /* 587 | ============================================== 588 | hatch 589 | ============================================== 590 | */ 591 | 592 | .hatch{ 593 | animation-name: hatch; 594 | -webkit-animation-name: hatch; 595 | 596 | animation-duration: 2s; 597 | -webkit-animation-duration: 2s; 598 | 599 | animation-timing-function: ease-in-out; 600 | -webkit-animation-timing-function: ease-in-out; 601 | 602 | transform-origin: 50% 100%; 603 | -ms-transform-origin: 50% 100%; 604 | -webkit-transform-origin: 50% 100%; 605 | 606 | visibility: visible !important; 607 | } 608 | 609 | @keyframes hatch { 610 | 0% { 611 | transform: rotate(0deg) scaleY(0.6); 612 | } 613 | 20% { 614 | transform: rotate(-2deg) scaleY(1.05); 615 | } 616 | 35% { 617 | transform: rotate(2deg) scaleY(1); 618 | } 619 | 50% { 620 | transform: rotate(-2deg); 621 | } 622 | 65% { 623 | transform: rotate(1deg); 624 | } 625 | 80% { 626 | transform: rotate(-1deg); 627 | } 628 | 100% { 629 | transform: rotate(0deg); 630 | } 631 | } 632 | 633 | @-webkit-keyframes hatch { 634 | 0% { 635 | -webkit-transform: rotate(0deg) scaleY(0.6); 636 | } 637 | 20% { 638 | -webkit-transform: rotate(-2deg) scaleY(1.05); 639 | } 640 | 35% { 641 | -webkit-transform: rotate(2deg) scaleY(1); 642 | } 643 | 50% { 644 | -webkit-transform: rotate(-2deg); 645 | } 646 | 65% { 647 | -webkit-transform: rotate(1deg); 648 | } 649 | 80% { 650 | -webkit-transform: rotate(-1deg); 651 | } 652 | 100% { 653 | -webkit-transform: rotate(0deg); 654 | } 655 | } 656 | 657 | 658 | /* 659 | ============================================== 660 | bounce 661 | ============================================== 662 | */ 663 | 664 | 665 | .bounce{ 666 | animation-name: bounce; 667 | -webkit-animation-name: bounce; 668 | 669 | animation-duration: 1.6s; 670 | -webkit-animation-duration: 1.6s; 671 | 672 | animation-timing-function: ease; 673 | -webkit-animation-timing-function: ease; 674 | 675 | transform-origin: 50% 100%; 676 | -ms-transform-origin: 50% 100%; 677 | -webkit-transform-origin: 50% 100%; 678 | } 679 | 680 | @keyframes bounce { 681 | 0% { 682 | transform: translateY(0%) scaleY(0.6); 683 | } 684 | 60%{ 685 | transform: translateY(-100%) scaleY(1.1); 686 | } 687 | 70%{ 688 | transform: translateY(0%) scaleY(0.95) scaleX(1.05); 689 | } 690 | 80%{ 691 | transform: translateY(0%) scaleY(1.05) scaleX(1); 692 | } 693 | 90%{ 694 | transform: translateY(0%) scaleY(0.95) scaleX(1); 695 | } 696 | 100%{ 697 | transform: translateY(0%) scaleY(1) scaleX(1); 698 | } 699 | } 700 | 701 | @-webkit-keyframes bounce { 702 | 0% { 703 | -webkit-transform: translateY(0%) scaleY(0.6); 704 | } 705 | 60%{ 706 | -webkit-transform: translateY(-100%) scaleY(1.1); 707 | } 708 | 70%{ 709 | -webkit-transform: translateY(0%) scaleY(0.95) scaleX(1.05); 710 | } 711 | 80%{ 712 | -webkit-transform: translateY(0%) scaleY(1.05) scaleX(1); 713 | } 714 | 90%{ 715 | -webkit-transform: translateY(0%) scaleY(0.95) scaleX(1); 716 | } 717 | 100%{ 718 | -webkit-transform: translateY(0%) scaleY(1) scaleX(1); 719 | } 720 | } 721 | 722 | 723 | /* 724 | ============================================== 725 | pulse 726 | ============================================== 727 | */ 728 | 729 | .pulse{ 730 | animation-name: pulse; 731 | -webkit-animation-name: pulse; 732 | 733 | animation-duration: 1.5s; 734 | -webkit-animation-duration: 1.5s; 735 | 736 | animation-iteration-count: infinite; 737 | -webkit-animation-iteration-count: infinite; 738 | } 739 | 740 | @keyframes pulse { 741 | 0% { 742 | transform: scale(0.9); 743 | opacity: 0.4; 744 | } 745 | 50% { 746 | transform: scale(1.1); 747 | opacity: 1; 748 | } 749 | 100% { 750 | transform: scale(0.9); 751 | opacity: 0.4; 752 | } 753 | } 754 | 755 | @-webkit-keyframes pulse { 756 | 0% { 757 | -webkit-transform: scale(0.95); 758 | opacity: 0.4; 759 | } 760 | 50% { 761 | -webkit-transform: scale(1.1); 762 | opacity: 1; 763 | } 764 | 100% { 765 | -webkit-transform: scale(0.95); 766 | opacity: 0.4; 767 | } 768 | } 769 | 770 | /* 771 | ============================================== 772 | floating 773 | ============================================== 774 | */ 775 | 776 | .floating{ 777 | animation-name: floating; 778 | -webkit-animation-name: floating; 779 | 780 | animation-duration: 1s; 781 | -webkit-animation-duration: 1s; 782 | 783 | animation-iteration-count: infinite; 784 | -webkit-animation-iteration-count: infinite; 785 | } 786 | 787 | @keyframes floating { 788 | 0% { 789 | transform: translateY(0%); 790 | } 791 | 50% { 792 | transform: translateY(8%); 793 | } 794 | 100% { 795 | transform: translateY(0%); 796 | } 797 | } 798 | 799 | @-webkit-keyframes floating { 800 | 0% { 801 | -webkit-transform: translateY(0%); 802 | } 803 | 50% { 804 | -webkit-transform: translateY(8%); 805 | } 806 | 100% { 807 | -webkit-transform: translateY(0%); 808 | } 809 | } 810 | 811 | /* 812 | ============================================== 813 | tossing 814 | ============================================== 815 | */ 816 | 817 | .tossing{ 818 | animation-name: tossing; 819 | -webkit-animation-name: tossing; 820 | 821 | animation-duration: 2.5s; 822 | -webkit-animation-duration: 2.5s; 823 | 824 | animation-iteration-count: infinite; 825 | -webkit-animation-iteration-count: infinite; 826 | } 827 | 828 | @keyframes tossing { 829 | 0% { 830 | transform: rotate(-4deg); 831 | } 832 | 50% { 833 | transform: rotate(4deg); 834 | } 835 | 100% { 836 | transform: rotate(-4deg); 837 | } 838 | } 839 | 840 | @-webkit-keyframes tossing { 841 | 0% { 842 | -webkit-transform: rotate(-4deg); 843 | } 844 | 50% { 845 | -webkit-transform: rotate(4deg); 846 | } 847 | 100% { 848 | -webkit-transform: rotate(-4deg); 849 | } 850 | } 851 | 852 | /* 853 | ============================================== 854 | pullUp 855 | ============================================== 856 | */ 857 | 858 | .pullUp{ 859 | animation-name: pullUp; 860 | -webkit-animation-name: pullUp; 861 | 862 | animation-duration: 1.1s; 863 | -webkit-animation-duration: 1.1s; 864 | 865 | animation-timing-function: ease-out; 866 | -webkit-animation-timing-function: ease-out; 867 | 868 | transform-origin: 50% 100%; 869 | -ms-transform-origin: 50% 100%; 870 | -webkit-transform-origin: 50% 100%; 871 | } 872 | 873 | @keyframes pullUp { 874 | 0% { 875 | transform: scaleY(0.1); 876 | } 877 | 40% { 878 | transform: scaleY(1.02); 879 | } 880 | 60% { 881 | transform: scaleY(0.98); 882 | } 883 | 80% { 884 | transform: scaleY(1.01); 885 | } 886 | 100% { 887 | transform: scaleY(0.98); 888 | } 889 | 80% { 890 | transform: scaleY(1.01); 891 | } 892 | 100% { 893 | transform: scaleY(1); 894 | } 895 | } 896 | 897 | @-webkit-keyframes pullUp { 898 | 0% { 899 | -webkit-transform: scaleY(0.1); 900 | } 901 | 40% { 902 | -webkit-transform: scaleY(1.02); 903 | } 904 | 60% { 905 | -webkit-transform: scaleY(0.98); 906 | } 907 | 80% { 908 | -webkit-transform: scaleY(1.01); 909 | } 910 | 100% { 911 | -webkit-transform: scaleY(0.98); 912 | } 913 | 80% { 914 | -webkit-transform: scaleY(1.01); 915 | } 916 | 100% { 917 | -webkit-transform: scaleY(1); 918 | } 919 | } 920 | 921 | /* 922 | ============================================== 923 | pullDown 924 | ============================================== 925 | */ 926 | 927 | .pullDown{ 928 | animation-name: pullDown; 929 | -webkit-animation-name: pullDown; 930 | 931 | animation-duration: 1.1s; 932 | -webkit-animation-duration: 1.1s; 933 | 934 | animation-timing-function: ease-out; 935 | -webkit-animation-timing-function: ease-out; 936 | 937 | transform-origin: 50% 0%; 938 | -ms-transform-origin: 50% 0%; 939 | -webkit-transform-origin: 50% 0%; 940 | } 941 | 942 | @keyframes pullDown { 943 | 0% { 944 | transform: scaleY(0.1); 945 | } 946 | 40% { 947 | transform: scaleY(1.02); 948 | } 949 | 60% { 950 | transform: scaleY(0.98); 951 | } 952 | 80% { 953 | transform: scaleY(1.01); 954 | } 955 | 100% { 956 | transform: scaleY(0.98); 957 | } 958 | 80% { 959 | transform: scaleY(1.01); 960 | } 961 | 100% { 962 | transform: scaleY(1); 963 | } 964 | } 965 | 966 | @-webkit-keyframes pullDown { 967 | 0% { 968 | -webkit-transform: scaleY(0.1); 969 | } 970 | 40% { 971 | -webkit-transform: scaleY(1.02); 972 | } 973 | 60% { 974 | -webkit-transform: scaleY(0.98); 975 | } 976 | 80% { 977 | -webkit-transform: scaleY(1.01); 978 | } 979 | 100% { 980 | -webkit-transform: scaleY(0.98); 981 | } 982 | 80% { 983 | -webkit-transform: scaleY(1.01); 984 | } 985 | 100% { 986 | -webkit-transform: scaleY(1); 987 | } 988 | } 989 | 990 | /* 991 | ============================================== 992 | stretchLeft 993 | ============================================== 994 | */ 995 | 996 | .stretchLeft{ 997 | animation-name: stretchLeft; 998 | -webkit-animation-name: stretchLeft; 999 | 1000 | animation-duration: 1.5s; 1001 | -webkit-animation-duration: 1.5s; 1002 | 1003 | animation-timing-function: ease-out; 1004 | -webkit-animation-timing-function: ease-out; 1005 | 1006 | transform-origin: 100% 0%; 1007 | -ms-transform-origin: 100% 0%; 1008 | -webkit-transform-origin: 100% 0%; 1009 | } 1010 | 1011 | @keyframes stretchLeft { 1012 | 0% { 1013 | transform: scaleX(0.3); 1014 | } 1015 | 40% { 1016 | transform: scaleX(1.02); 1017 | } 1018 | 60% { 1019 | transform: scaleX(0.98); 1020 | } 1021 | 80% { 1022 | transform: scaleX(1.01); 1023 | } 1024 | 100% { 1025 | transform: scaleX(0.98); 1026 | } 1027 | 80% { 1028 | transform: scaleX(1.01); 1029 | } 1030 | 100% { 1031 | transform: scaleX(1); 1032 | } 1033 | } 1034 | 1035 | @-webkit-keyframes stretchLeft { 1036 | 0% { 1037 | -webkit-transform: scaleX(0.3); 1038 | } 1039 | 40% { 1040 | -webkit-transform: scaleX(1.02); 1041 | } 1042 | 60% { 1043 | -webkit-transform: scaleX(0.98); 1044 | } 1045 | 80% { 1046 | -webkit-transform: scaleX(1.01); 1047 | } 1048 | 100% { 1049 | -webkit-transform: scaleX(0.98); 1050 | } 1051 | 80% { 1052 | -webkit-transform: scaleX(1.01); 1053 | } 1054 | 100% { 1055 | -webkit-transform: scaleX(1); 1056 | } 1057 | } 1058 | 1059 | /* 1060 | ============================================== 1061 | stretchRight 1062 | ============================================== 1063 | */ 1064 | 1065 | .stretchRight{ 1066 | animation-name: stretchRight; 1067 | -webkit-animation-name: stretchRight; 1068 | 1069 | animation-duration: 1.5s; 1070 | -webkit-animation-duration: 1.5s; 1071 | 1072 | animation-timing-function: ease-out; 1073 | -webkit-animation-timing-function: ease-out; 1074 | 1075 | transform-origin: 0% 0%; 1076 | -ms-transform-origin: 0% 0%; 1077 | -webkit-transform-origin: 0% 0%; 1078 | } 1079 | 1080 | @keyframes stretchRight { 1081 | 0% { 1082 | transform: scaleX(0.3); 1083 | } 1084 | 40% { 1085 | transform: scaleX(1.02); 1086 | } 1087 | 60% { 1088 | transform: scaleX(0.98); 1089 | } 1090 | 80% { 1091 | transform: scaleX(1.01); 1092 | } 1093 | 100% { 1094 | transform: scaleX(0.98); 1095 | } 1096 | 80% { 1097 | transform: scaleX(1.01); 1098 | } 1099 | 100% { 1100 | transform: scaleX(1); 1101 | } 1102 | } 1103 | 1104 | @-webkit-keyframes stretchRight { 1105 | 0% { 1106 | -webkit-transform: scaleX(0.3); 1107 | } 1108 | 40% { 1109 | -webkit-transform: scaleX(1.02); 1110 | } 1111 | 60% { 1112 | -webkit-transform: scaleX(0.98); 1113 | } 1114 | 80% { 1115 | -webkit-transform: scaleX(1.01); 1116 | } 1117 | 100% { 1118 | -webkit-transform: scaleX(0.98); 1119 | } 1120 | 80% { 1121 | -webkit-transform: scaleX(1.01); 1122 | } 1123 | 100% { 1124 | -webkit-transform: scaleX(1); 1125 | } 1126 | } 1127 | -------------------------------------------------------------------------------- /app/assets/stylesheets/vendor/_index.scss: -------------------------------------------------------------------------------- 1 | @import "animation_cheat_sheet"; 2 | -------------------------------------------------------------------------------- /app/channels/application_cable/channel.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Channel < ActionCable::Channel::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/channels/application_cable/connection.rb: -------------------------------------------------------------------------------- 1 | module ApplicationCable 2 | class Connection < ActionCable::Connection::Base 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | protect_from_forgery with: :exception 3 | before_action :authenticate_user! 4 | before_action :configure_permitted_parameters, if: :devise_controller? 5 | 6 | def configure_permitted_parameters 7 | # For additional fields in app/views/devise/registrations/new.html.erb 8 | devise_parameter_sanitizer.permit(:sign_up, keys: [:first_name, :last_name, :gender, :gender_preferences, :description, :photo ]) 9 | 10 | # For additional in app/views/devise/registrations/edit.html.erb 11 | devise_parameter_sanitizer.permit(:account_update, keys: [:username, :first_name, :last_name, :gender, :gender_preferences, :description, :photo ]) 12 | end 13 | 14 | 15 | 16 | end 17 | -------------------------------------------------------------------------------- /app/controllers/beds_controller.rb: -------------------------------------------------------------------------------- 1 | class BedsController < ApplicationController 2 | skip_before_action :authenticate_user!, only: [:new, :index] 3 | 4 | def index 5 | @beds = Bed.all 6 | 7 | @beds = Bed.where.not(latitude: nil, longitude: nil) 8 | 9 | @hash = Gmaps4rails.build_markers(@beds) do |bed, marker| 10 | marker.lat bed.latitude 11 | marker.lng bed.longitude 12 | # marker.infowindow render_to_string(partial: "/flats/map_box", locals: { flat: flat }) 13 | end 14 | end 15 | 16 | def new 17 | @bed = Bed.new 18 | # @user = current_user 19 | end 20 | 21 | def create 22 | @bed = Bed.create(bed_params) 23 | @bed.user = current_user 24 | if @bed.save 25 | redirect_to bed_path(@bed) 26 | else 27 | render :new 28 | end 29 | end 30 | 31 | def show 32 | set_bed 33 | 34 | @booking = Booking.new 35 | @checkin = params['checkin_on'] 36 | @checkout = params['checkout_on'] 37 | if ((!@checkin.blank?) && (!@checkout.blank?)) 38 | from = @checkin.split("/") 39 | to = @checkout.split("/") 40 | start = Date.new(from[2].to_f, from[1].to_f - 1, from[0].to_f) 41 | finish = Date.new(to[2].to_f, to[1].to_f - 1, to[0].to_f) 42 | @nb_days = (finish - start).to_f 43 | @total_price = (@nb_days * @bed.price.to_f).round 44 | end 45 | @bed = Bed.find(params[:id]) 46 | @bookings = @bed.bookings 47 | @alert_message = "You are viewing the bed of #{@bed.user.first_name}" 48 | end 49 | 50 | def edit 51 | set_bed 52 | end 53 | 54 | 55 | def update 56 | set_bed 57 | @bed.update(bed_params) 58 | redirect_to bed_path(@bed) 59 | end 60 | 61 | def destroy 62 | set_bed 63 | @bed.destroy 64 | redirect_to root_path 65 | end 66 | 67 | 68 | private 69 | 70 | def bed_params 71 | params.require(:bed).permit(:address, :title, :photo, :price, :description, :country, :city, :zipcode, :photo, :blanket_type, :pillow, :breakfast) 72 | end 73 | 74 | def set_bed 75 | @bed = Bed.find(params[:id]) 76 | end 77 | 78 | end 79 | -------------------------------------------------------------------------------- /app/controllers/bookings_controller.rb: -------------------------------------------------------------------------------- 1 | class BookingsController < ApplicationController 2 | 3 | 4 | def create 5 | @bed = Bed.find(params[:bed_id]) 6 | @booking = Booking.new(booking_params) 7 | @booking.bed = @bed 8 | @booking.user = current_user 9 | @booking.status = "Pending host validation" 10 | if @booking.checkout_on && @booking.checkin_on 11 | @booking.value = (@booking.checkout_on - @booking.checkin_on).to_f * @booking.bed.price.to_f 12 | else 13 | @booking.value = 0 14 | end 15 | if @booking.save 16 | redirect_to booking_path(@booking) 17 | else 18 | redirect_to bed_path(@bed) 19 | end 20 | end 21 | 22 | def index 23 | @bookings = Booking.where(user_id: current_user.id) 24 | @review = Review.new 25 | end 26 | 27 | def show 28 | set_booking 29 | @bed = @booking.bed 30 | end 31 | 32 | def update 33 | set_booking 34 | @booking.status = "Pending host validation" 35 | @booking.save! 36 | redirect_to booking_path(@booking) 37 | end 38 | 39 | def destroy 40 | set_booking 41 | @booking.destroy 42 | redirect_to root_path 43 | end 44 | 45 | private 46 | 47 | def booking_params 48 | params.require(:booking).permit(:checkin_on, :checkout_on, :value, :status) 49 | end 50 | 51 | def set_booking 52 | @booking = Booking.find(params[:id]) 53 | end 54 | 55 | end 56 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/my/beds_controller.rb: -------------------------------------------------------------------------------- 1 | class My::BedsController < ApplicationController 2 | def index 3 | @beds = current_user.beds 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /app/controllers/my/bookings_controller.rb: -------------------------------------------------------------------------------- 1 | class My::BookingsController < ApplicationController 2 | def index 3 | @beds = current_user.beds 4 | end 5 | 6 | def update 7 | set_booking 8 | @booking.update(set_params) 9 | redirect_to my_bookings_path 10 | end 11 | 12 | 13 | private 14 | 15 | def set_booking 16 | @booking = Booking.find(params[:id]) 17 | end 18 | 19 | def set_params 20 | params.require(:booking).permit(:status) 21 | end 22 | 23 | end 24 | 25 | -------------------------------------------------------------------------------- /app/controllers/pages_controller.rb: -------------------------------------------------------------------------------- 1 | class PagesController < ApplicationController 2 | skip_before_action :authenticate_user!, only: :home 3 | 4 | def home 5 | @bed = Bed.new 6 | @beds = Bed.all 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/controllers/reviews_controller.rb: -------------------------------------------------------------------------------- 1 | class ReviewsController < ApplicationController 2 | before_action :set_booking, only: [:new, :create] 3 | def new 4 | @review = Review.new 5 | end 6 | 7 | def create 8 | @review = Review.new(review_params) 9 | @review.booking = @booking 10 | @review.save 11 | redirect_to bookings_path 12 | end 13 | 14 | private 15 | def set_booking 16 | @booking = Booking.find(params[:booking_id]) 17 | end 18 | 19 | def review_params 20 | params.require(:review).permit(:content, :rating) 21 | end 22 | end 23 | 24 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/beds_helper.rb: -------------------------------------------------------------------------------- 1 | module BedsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/bookings_helper.rb: -------------------------------------------------------------------------------- 1 | module BookingsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/helpers/reviews_helper.rb: -------------------------------------------------------------------------------- 1 | module ReviewsHelper 2 | end 3 | -------------------------------------------------------------------------------- /app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | end 3 | -------------------------------------------------------------------------------- /app/mailers/application_mailer.rb: -------------------------------------------------------------------------------- 1 | class ApplicationMailer < ActionMailer::Base 2 | default from: 'from@example.com' 3 | layout 'mailer' 4 | end 5 | -------------------------------------------------------------------------------- /app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | self.abstract_class = true 3 | end 4 | -------------------------------------------------------------------------------- /app/models/bed.rb: -------------------------------------------------------------------------------- 1 | class Bed < ApplicationRecord 2 | 3 | geocoded_by :address 4 | after_validation :geocode, if: :address_changed? 5 | 6 | BLANKET = ["Wool blanket", "duvet", "sleeping bag", "none"] 7 | 8 | belongs_to :user 9 | validates :address, presence: true 10 | validates :title, presence: true 11 | validates :photo, presence: true 12 | validates :price, presence: true 13 | validates :city, presence: true 14 | validates :country, presence: true 15 | validates :blanket_type, inclusion: { in: BLANKET, 16 | message: "%{value} is not a valid blanket type" }, presence: true 17 | 18 | has_many :bookings, dependent: :destroy 19 | has_many :reviews, through: :bookings 20 | has_attachment :photo 21 | end 22 | 23 | -------------------------------------------------------------------------------- /app/models/booking.rb: -------------------------------------------------------------------------------- 1 | class Booking < ApplicationRecord 2 | belongs_to :user 3 | belongs_to :bed 4 | has_one :review 5 | validates :checkin_on, presence: true 6 | validates :checkout_on, presence: true 7 | validates :status, inclusion: { in: ["Pending guest request", "Pending host validation", "Confirmed", "Canceled"], allow_nil: true } 8 | end 9 | -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/models/review.rb: -------------------------------------------------------------------------------- 1 | class Review < ApplicationRecord 2 | belongs_to :booking 3 | validates :content, presence: true 4 | validates :rating, presence: true 5 | end 6 | -------------------------------------------------------------------------------- /app/models/user.rb: -------------------------------------------------------------------------------- 1 | class User < ApplicationRecord 2 | # Include default devise modules. Others available are: 3 | # :confirmable, :lockable, :timeoutable and :omniauthable 4 | GENDER = %w(Woman Man Both) 5 | devise :database_authenticatable, :registerable, 6 | :recoverable, :rememberable, :trackable, :validatable 7 | validates :first_name, presence: true 8 | validates :gender, presence: true, inclusion: { in: GENDER, 9 | message: "%{value} is not a valid gender" } 10 | validates :photo, presence: true 11 | validates :email, presence: true, uniqueness: true 12 | validates :encrypted_password, presence: true 13 | has_many :beds, dependent: :destroy 14 | has_many :bookings 15 | has_many :reviews, through: :bookings 16 | # has_many :bookings, through: :beds 17 | has_attachment :photo 18 | end 19 | -------------------------------------------------------------------------------- /app/views/beds/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Modify your bed description so that it is even sexier !

2 |
3 |
4 |
5 | 30 |
31 |
32 |
33 | -------------------------------------------------------------------------------- /app/views/beds/index.html.erb: -------------------------------------------------------------------------------- 1 |

Find your Sharer and a comfy bed

2 | 3 | 4 |
5 | 6 |
7 |
8 | <% @beds.each do |bed| %> 9 |
10 | <%= link_to bed_path(bed,checkin_on: params[:checkin], checkout_on: params[:checkout]) do %> 11 |
12 |
14 |
<%= bed.user.first_name %>
15 | <%= cl_image_tag bed.user.photo.path, width: 50, height: 50, crop: :thumb, gravity: :face, class: "card-user avatar" %> 16 |
17 |
18 |
19 |

<%= bed.city %>

20 |

<%= bed.title %>

21 |
22 |
23 |

<%= bed.price %> €

24 |
25 |
26 |
27 | <% end %> 28 |
29 | <% end %> 30 |
31 |
32 | 33 |
34 |
35 |
36 |
37 |
38 |
39 | 40 | <% content_for(:after_js) do %> 41 | <%= javascript_tag do %> 42 | $(document).ready(function() { 43 | var handler = Gmaps.build('Google'); 44 | handler.buildMap({ 45 | provider: { 46 | scrollwheel: false, 47 | zoomControl: false 48 | }, 49 | internal: { id: 'beds-map' } }, function() { 50 | markers = handler.addMarkers(<%= raw @hash.to_json %>); 51 | handler.bounds.extendWith(markers); 52 | handler.fitMapToBounds(); 53 | if (markers.length == 0) { 54 | handler.getMap().setZoom(2); 55 | } else if (markers.length == 1) { 56 | handler.getMap().setZoom(14); 57 | } 58 | }); 59 | }); 60 | 61 | <% end %> 62 | <% end %> 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /app/views/beds/new.html.erb: -------------------------------------------------------------------------------- 1 |

Share your bed with the community. Be fun and sexy !

2 | 3 |
4 |
5 | 31 |
32 | 33 |
34 | 35 | 36 | 37 | <%= content_for(:after_js) do %> 38 | 39 | <% end %> 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/views/beds/show.html.erb: -------------------------------------------------------------------------------- 1 |

<%= @bed.title %>

2 | 3 |
4 | 5 |
6 |
7 |
8 |
10 |
11 |
12 | 13 |
14 |
15 |
<%= @bed.user.first_name %>
16 |
17 |

Sex: <%= @bed.user.gender %>

18 |

Interested in: <%= @bed.user.gender_preferences %>

19 | 20 | " <%= @bed.user.description %> " 21 |
22 | <%= cl_image_tag @bed.user.photo.path, width: 50, height: 50, class: "wagoncard-user avatar avatar-semi" %> 23 |
24 |
25 |
26 |
27 | 28 |
29 |
30 | 31 |

<%= @bed.address %> <%= @bed.city %> <%= @bed.country %>

32 |

<%= @bed.price %> per night ... but so much love

33 |

Description:

34 |

<%= @bed.description %>

35 |
36 |

Equipments

37 | 38 | <%= image_tag "pillow.jpg", class: "equipment" %> 39 | <% if @bed.pillow %> 40 | 41 | <% else %> 42 | 43 | <% end %> 44 | 45 | 46 | <% if @bed.breakfast %> 47 | 48 | <% else %> 49 | 50 | <% end %> 51 |
52 | 53 |
54 |

Reviews

55 | <% @bookings.each do |booking|%> 56 |
    57 | <% if booking.review %> 58 |
  • 59 |
    60 | <%= cl_image_tag booking.user.photo.path, width: 50, height: 50, crop: :thumb, gravity: :face, class: "avatar" %> 61 |
    62 | <% booking.review.rating.times do %> 63 | 64 | <% end %> 65 | <% (5- booking.review.rating).times do %> 66 | 67 | <% end %> 68 |

    <%= booking.review.content %>

    69 |
    70 |
    71 |
  • 72 | <% end %> 73 |
74 | <% end %> 75 |
76 | 77 |
78 | 79 |
80 |
81 | <%= simple_form_for [@bed, @booking] do |f| %> 82 | 83 |
84 |
85 |

From

86 | <%= f.text_field :checkin_on, class: "datepicker checkin_on", value: @checkin, placeholder: "dd/mm/yyyy" %> 87 |
88 |
89 |

To

90 | <%= f.text_field :checkout_on, class: "datepicker checkout_on", value: @checkout, placeholder: "dd/mm/yyyy" %> 91 |
92 |

Total price: <%= @total_price %> €

93 | <%= f.submit "Book", class: "btn btn-danger"%> 94 |
95 | 96 | <% end%> 97 | 98 |
99 |
100 |
101 |
102 | 103 |
104 | 105 | 106 | <% content_for(:after_js) do %> 107 | 108 | 109 | 141 | 142 | <% end %> 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | -------------------------------------------------------------------------------- /app/views/bookings/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

All my stays

3 |
4 |
5 |

MY FUTURE NIGHTS

6 |
7 | 8 |
9 | 69 |
70 | 71 |
72 | 73 |
74 |

MY PAST NIGHTS

75 |
76 | 77 |
78 | 118 |
119 | 120 | 121 | -------------------------------------------------------------------------------- /app/views/bookings/show.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | <% if @booking.status == "Pending host validation"%> 5 |

We are waiting for <%= @booking.bed.user.first_name %> to confirm your request

6 |

So... stay tuned!

7 | <% end %> 8 |
9 | 10 |
11 |
12 | <%= cl_image_tag @booking.bed.user.photo.path, width: 150, height: 150, crop: :thumb, class: "avatar-xlarge" %> 13 |
14 |
15 |
16 |

Reminder of your booking details

17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 |

  Your host is <%= @booking.bed.user.first_name %>

  You asked to join a warm bed from :
  <%= @booking.checkin_on %> to <%= @booking.checkout_on %>

  The total price for your booking is <%= @booking.value %> €

34 |
35 |
36 |
37 | 38 | 39 | <% if @booking.status == "Pending guest request"%> 40 | <%= simple_form_for(@booking) do |f| %> 41 | <%= f.submit "Confirm my booking", class: "btn btn-danger btn-lg" %> 42 | <% end %> 43 | <% end %> 44 |
45 | <%= link_to "See my next stays", bookings_path, class:"btn btn-default btn-lg " %> 46 |
47 |
48 |
49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /app/views/devise/confirmations/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /app/views/devise/mailer/confirmation_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Welcome <%= @email %>!

2 | 3 |

You can confirm your account email through the link below:

4 | 5 |

<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>

6 | -------------------------------------------------------------------------------- /app/views/devise/mailer/password_change.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

We're contacting you to notify you that your password has been changed.

4 | -------------------------------------------------------------------------------- /app/views/devise/mailer/reset_password_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

Someone has requested a link to change your password. You can do this through the link below.

4 | 5 |

<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>

6 | 7 |

If you didn't request this, please ignore this email.

8 |

Your password won't change until you access the link above and create a new one.

9 | -------------------------------------------------------------------------------- /app/views/devise/mailer/unlock_instructions.html.erb: -------------------------------------------------------------------------------- 1 |

Hello <%= @resource.email %>!

2 | 3 |

Your account has been locked due to an excessive number of unsuccessful sign in attempts.

4 | 5 |

Click the link below to unlock your account:

6 | 7 |

<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>

8 | -------------------------------------------------------------------------------- /app/views/devise/passwords/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Change your password

2 | 3 | <%= simple_form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> 4 | <%= f.error_notification %> 5 | 6 | <%= f.input :reset_password_token, as: :hidden %> 7 | <%= f.full_error :reset_password_token %> 8 | 9 |
10 | <%= f.input :password, label: "New password", required: true, autofocus: true, hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length) %> 11 | <%= f.input :password_confirmation, label: "Confirm your new password", required: true %> 12 |
13 | 14 |
15 | <%= f.button :submit, "Change my password" %> 16 |
17 | <% end %> 18 | 19 | <%= render "devise/shared/links" %> 20 | -------------------------------------------------------------------------------- /app/views/devise/passwords/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 20 |
21 |
22 | 23 |
24 | -------------------------------------------------------------------------------- /app/views/devise/registrations/edit.html.erb: -------------------------------------------------------------------------------- 1 |

Edit <%= resource_name.to_s.humanize %>

2 | 3 | <%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> 4 | <%= f.error_notification %> 5 | 6 |
7 | <%= f.input :email, required: true, autofocus: true %> 8 | 9 | <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> 10 |

Currently waiting confirmation for: <%= resource.unconfirmed_email %>

11 | <% end %> 12 | 13 | <%= f.input :password, autocomplete: "off", hint: "leave it blank if you don't want to change it", required: false %> 14 | <%= f.input :password_confirmation, required: false %> 15 | <%= f.input :current_password, hint: "we need your current password to confirm your changes", required: true %> 16 |
17 | 18 |
19 | <%= f.button :submit, "Update" %> 20 |
21 | <% end %> 22 | 23 |

Cancel my account

24 | 25 |

Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>

26 | 27 | <%= link_to "Back", :back %> 28 | -------------------------------------------------------------------------------- /app/views/devise/registrations/new.html.erb: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |
6 |

Sign up

7 |
8 | <%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> 9 | <%= f.error_notification %> 10 | 11 |
12 |

<%= f.input :first_name, required: true %>

13 |

<%= f.input :gender, required: true, collection: User::GENDER %>

14 |

<%= f.input :email, required: true, autofocus: true %>

15 |

<%= f.input :password, required: true, hint: ("#{@minimum_password_length}characters minimum" if @minimum_password_length) %>

16 |

<%= f.input :password_confirmation, required: true %>

17 |

<%= f.input :gender_preferences, collection: User::GENDER %>

18 |

<%= f.input :description %>

19 |
20 |

<%= f.input :photo, as: :attachinary, required: true %>

21 |
22 |
23 |
24 | <%= f.button :submit, "Sign up", class:"btn btn-medium" %> 25 |
26 |
27 |
28 | <%= render "devise/shared/links" %> 29 | <% end %> 30 |
31 |
32 |
33 | 34 | -------------------------------------------------------------------------------- /app/views/devise/sessions/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |

Login

6 |
7 | <%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> 8 |
9 | <%= f.input :email, required: false, autofocus: true %> 10 | <%= f.input :password, required: false %> 11 | <%= f.input :remember_me, as: :boolean if devise_mapping.rememberable? %> 12 |
13 |
14 | <%= f.button :submit, "Log in", class:"btn btn-danger" %> 15 |
16 |
17 |
18 | <%= render "devise/shared/links" %> 19 | <% end %> 20 |
21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /app/views/devise/shared/_links.html.erb: -------------------------------------------------------------------------------- 1 | <%- if controller_name != 'sessions' %> 2 | <%= link_to "Log in", new_session_path(resource_name) %>
3 | <% end -%> 4 | 5 | <%- if devise_mapping.registerable? && controller_name != 'registrations' %> 6 | <%= link_to "Sign up", new_registration_path(resource_name) %>
7 | <% end -%> 8 | 9 | <%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> 10 | <%= link_to "Forgot your password?", new_password_path(resource_name) %>
11 | <% end -%> 12 | 13 | <%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> 14 | <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
15 | <% end -%> 16 | 17 | <%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> 18 | <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
19 | <% end -%> 20 | 21 | <%- if devise_mapping.omniauthable? %> 22 | <%- resource_class.omniauth_providers.each do |provider| %> 23 | <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %>
24 | <% end -%> 25 | <% end -%> 26 | -------------------------------------------------------------------------------- /app/views/devise/unlocks/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ShareAbed 10 | <%= csrf_meta_tags %> 11 | <%= action_cable_meta_tag %> 12 | <%= stylesheet_link_tag 'application', media: 'all' %> 13 | 14 | 15 | 16 | <%= render 'shared/navbar' %> 17 | <%= render 'shared/flashes' %> 18 |
19 | <%= yield %> 20 |
21 | <%= javascript_include_tag "https://maps.google.com/maps/api/js?libraries=places&key=#{ENV['GOOGLE_API_BROWSER_KEY']}" %> 22 | 23 | <%= javascript_include_tag "https://cdn.rawgit.com/printercu/google-maps-utility-library-v3-read-only/master/markerclusterer/src/markerclusterer_compiled.js" %> 24 | <%= javascript_include_tag "https://cdn.rawgit.com/printercu/google-maps-utility-library-v3-read-only/master/infobox/src/infobox_packed.js" %> 25 | 26 | 27 | <%= javascript_include_tag "application" %> 28 | <%= yield(:after_js) %> 29 | <%= cloudinary_js_config %> 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | <%= yield %> 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/views/layouts/mailer.text.erb: -------------------------------------------------------------------------------- 1 | <%= yield %> 2 | -------------------------------------------------------------------------------- /app/views/my/beds/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

Here are all the beds you are sharing!

3 |
4 | 5 | 6 |
7 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /app/views/my/bookings/index.html.erb: -------------------------------------------------------------------------------- 1 |
2 |

Wahou ! You are so attractive

3 |

See who wants to sleep with you !

4 |
5 | 6 |
7 | 8 | 63 |
64 | 65 | 66 | -------------------------------------------------------------------------------- /app/views/pages/home.html.erb: -------------------------------------------------------------------------------- 1 | 21 | 22 |

Some of the warmest beds and hosts in the community

23 | 24 |
25 |
26 | <% @beds.last(6).each do |bed| %> 27 |
28 | <%= link_to bed_path(bed) do %> 29 |
30 |
32 |
<%= bed.user.first_name %>
33 | <%= cl_image_tag bed.user.photo.path, width: 50, height: 50, crop: :thumb, gravity: :face, class: "card-user avatar" %> 34 |
35 |
36 |
37 |

<%= bed.city %>

38 |

<%= bed.title %>

39 |
40 |
41 |

<%= bed.price %> €

42 |
43 |
44 |
45 | <% end %> 46 |
47 | <% end %> 48 |
49 |
50 | 51 | -------------------------------------------------------------------------------- /app/views/reviews/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= simple_form_for [ booking, review ], url: booking_reviews_path(booking), method: :post do |form| %> 2 | <%= form.input :content, as: :text %> 3 | <%= form.input :rating%> 4 | <%= form.button :submit %> 5 | <% end %> 6 | -------------------------------------------------------------------------------- /app/views/shared/_flashes.html.erb: -------------------------------------------------------------------------------- 1 | <% if notice %> 2 | 6 | <% end %> 7 | <% if alert %> 8 | 12 | <% end %> 13 | -------------------------------------------------------------------------------- /app/views/shared/_footer.html.erb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/app/views/shared/_footer.html.erb -------------------------------------------------------------------------------- /app/views/shared/_navbar.html.erb: -------------------------------------------------------------------------------- 1 | 85 | 86 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/figaro: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # frozen_string_literal: true 3 | # 4 | # This file was generated by Bundler. 5 | # 6 | # The application 'figaro' is installed as part of a gem, and 7 | # this file is here to facilitate running it. 8 | # 9 | 10 | require "pathname" 11 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", 12 | Pathname.new(__FILE__).realpath) 13 | 14 | require "rubygems" 15 | require "bundler/setup" 16 | 17 | load Gem.bin_path("figaro", "figaro") 18 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | APP_PATH = File.expand_path('../config/application', __dir__) 8 | require_relative '../config/boot' 9 | require 'rails/commands' 10 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path('../spring', __FILE__) 4 | rescue LoadError => e 5 | raise unless e.message.include?('spring') 6 | end 7 | require_relative '../config/boot' 8 | require 'rake' 9 | Rake.application.run 10 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a starting point to setup your application. 15 | # Add necessary setup steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | # puts "\n== Copying sample files ==" 22 | # unless File.exist?('config/database.yml') 23 | # cp 'config/database.yml.sample', 'config/database.yml' 24 | # end 25 | 26 | puts "\n== Preparing database ==" 27 | system! 'bin/rails db:setup' 28 | 29 | puts "\n== Removing old logs and tempfiles ==" 30 | system! 'bin/rails log:clear tmp:clear' 31 | 32 | puts "\n== Restarting application server ==" 33 | system! 'bin/rails restart' 34 | end 35 | -------------------------------------------------------------------------------- /bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads spring without using Bundler, in order to be fast. 4 | # It gets overwritten when you run the `spring binstub` command. 5 | 6 | unless defined?(Spring) 7 | require 'rubygems' 8 | require 'bundler' 9 | 10 | lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read) 11 | spring = lockfile.specs.detect { |spec| spec.name == "spring" } 12 | if spring 13 | Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path 14 | gem 'spring', spring.version 15 | require 'spring/binstub' 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /bin/update: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | require 'fileutils' 4 | include FileUtils 5 | 6 | # path to your application root. 7 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 8 | 9 | def system!(*args) 10 | system(*args) || abort("\n== Command #{args} failed ==") 11 | end 12 | 13 | chdir APP_ROOT do 14 | # This script is a way to update your development environment automatically. 15 | # Add necessary update steps to this file. 16 | 17 | puts '== Installing dependencies ==' 18 | system! 'gem install bundler --conservative' 19 | system('bundle check') || system!('bundle install') 20 | 21 | puts "\n== Updating database ==" 22 | system! 'bin/rails db:migrate' 23 | 24 | puts "\n== Removing old logs and tempfiles ==" 25 | system! 'bin/rails log:clear tmp:clear' 26 | 27 | puts "\n== Restarting application server ==" 28 | system! 'bin/rails restart' 29 | end 30 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative 'config/environment' 4 | 5 | run Rails.application 6 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative 'boot' 2 | 3 | require "rails" 4 | # Pick the frameworks you want: 5 | require "active_model/railtie" 6 | require "active_job/railtie" 7 | require "active_record/railtie" 8 | require "action_controller/railtie" 9 | require "action_mailer/railtie" 10 | require "action_view/railtie" 11 | require "action_cable/engine" 12 | require "sprockets/railtie" 13 | # require "rails/test_unit/railtie" 14 | require "attachinary/orm/active_record" 15 | 16 | # Require the gems listed in Gemfile, including any gems 17 | # you've limited to :test, :development, or :production. 18 | Bundler.require(*Rails.groups) 19 | 20 | module RailsAirbnbClone 21 | class Application < Rails::Application 22 | config.generators do |generate| 23 | generate.assets false 24 | end 25 | 26 | # Settings in config/environments/* take precedence over those specified here. 27 | # Application configuration should go into files in config/initializers 28 | # -- all .rb files in that directory are automatically loaded. 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /config/cable.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: async 3 | 4 | test: 5 | adapter: async 6 | 7 | production: 8 | adapter: redis 9 | url: redis://localhost:6379/1 10 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | # PostgreSQL. Versions 9.1 and up are supported. 2 | # 3 | # Install the pg driver: 4 | # gem install pg 5 | # On OS X with Homebrew: 6 | # gem install pg -- --with-pg-config=/usr/local/bin/pg_config 7 | # On OS X with MacPorts: 8 | # gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config 9 | # On Windows: 10 | # gem install pg 11 | # Choose the win32 build. 12 | # Install PostgreSQL and put its /bin directory on your path. 13 | # 14 | # Configure Using Gemfile 15 | # gem 'pg' 16 | # 17 | default: &default 18 | adapter: postgresql 19 | encoding: unicode 20 | # For details on connection pooling, see rails configuration guide 21 | # http://guides.rubyonrails.org/configuring.html#database-pooling 22 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 23 | 24 | development: 25 | <<: *default 26 | database: rails-airbnb-clone_development 27 | 28 | # The specified database role being used to connect to postgres. 29 | # To create additional roles in postgres see `$ createuser --help`. 30 | # When left blank, postgres will use the default role. This is 31 | # the same name as the operating system user that initialized the database. 32 | #username: rails-airbnb-clone 33 | 34 | # The password associated with the postgres role (username). 35 | #password: 36 | 37 | # Connect on a TCP socket. Omitted by default since the client uses a 38 | # domain socket that doesn't need configuration. Windows does not have 39 | # domain sockets, so uncomment these lines. 40 | host: localhost 41 | 42 | # The TCP port the server listens on. Defaults to 5432. 43 | # If your server runs on a different port number, change accordingly. 44 | #port: 5432 45 | 46 | # Schema search path. The server defaults to $user,public 47 | #schema_search_path: myapp,sharedapp,public 48 | 49 | # Minimum log levels, in increasing order: 50 | # debug5, debug4, debug3, debug2, debug1, 51 | # log, notice, warning, error, fatal, and panic 52 | # Defaults to warning. 53 | #min_messages: notice 54 | 55 | # Warning: The database defined as "test" will be erased and 56 | # re-generated from your development database when you run "rake". 57 | # Do not set this db to the same as development or production. 58 | test: 59 | <<: *default 60 | database: rails-airbnb-clone_test 61 | 62 | # As with config/secrets.yml, you never want to store sensitive information, 63 | # like your database password, in your source code. If your source code is 64 | # ever seen by anyone, they now have access to your database. 65 | # 66 | # Instead, provide the password as a unix environment variable when you boot 67 | # the app. Read http://guides.rubyonrails.org/configuring.html#configuring-a-database 68 | # for a full rundown on how to provide these environment variables in a 69 | # production deployment. 70 | # 71 | # On Heroku and other platform providers, you may have a full connection URL 72 | # available as an environment variable. For example: 73 | # 74 | # DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase" 75 | # 76 | # You can use this database configuration with: 77 | # 78 | # production: 79 | # url: <%= ENV['DATABASE_URL'] %> 80 | # 81 | production: 82 | <<: *default 83 | database: rails-airbnb-clone_production 84 | username: rails-airbnb-clone 85 | password: <%= ENV['RAILS-AIRBNB-CLONE_DATABASE_PASSWORD'] %> 86 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative 'application' 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # In the development environment your application's code is reloaded on 5 | # every request. This slows down response time but is perfect for development 6 | # since you don't have to restart the web server when you make code changes. 7 | config.cache_classes = false 8 | 9 | # Do not eager load code on boot. 10 | config.eager_load = false 11 | 12 | # Show full error reports. 13 | config.consider_all_requests_local = true 14 | 15 | # Enable/disable caching. By default caching is disabled. 16 | if Rails.root.join('tmp/caching-dev.txt').exist? 17 | config.action_controller.perform_caching = true 18 | 19 | config.cache_store = :memory_store 20 | config.public_file_server.headers = { 21 | 'Cache-Control' => 'public, max-age=172800' 22 | } 23 | else 24 | config.action_controller.perform_caching = false 25 | 26 | config.cache_store = :null_store 27 | end 28 | 29 | # Don't care if the mailer can't send. 30 | config.action_mailer.raise_delivery_errors = false 31 | 32 | config.action_mailer.perform_caching = false 33 | 34 | # Print deprecation notices to the Rails logger. 35 | config.active_support.deprecation = :log 36 | 37 | # Raise an error on page load if there are pending migrations. 38 | config.active_record.migration_error = :page_load 39 | 40 | # Debug mode disables concatenation and preprocessing of assets. 41 | # This option may cause significant delays in view rendering with a large 42 | # number of complex assets. 43 | config.assets.debug = false 44 | 45 | # Suppress logger output for asset requests. 46 | config.assets.quiet = true 47 | 48 | 49 | config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } 50 | 51 | # Raises error for missing translations 52 | # config.action_view.raise_on_missing_translations = true 53 | 54 | # Use an evented file watcher to asynchronously detect changes in source code, 55 | # routes, locales, etc. This feature depends on the listen gem. 56 | config.file_watcher = ActiveSupport::EventedFileUpdateChecker 57 | end 58 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Disable serving static files from the `/public` folder by default since 18 | # Apache or NGINX already handles this. 19 | config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? 20 | 21 | # Compress JavaScripts and CSS. 22 | config.assets.js_compressor = :uglifier 23 | # config.assets.css_compressor = :sass 24 | 25 | # Do not fallback to assets pipeline if a precompiled asset is missed. 26 | config.assets.compile = false 27 | 28 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb 29 | 30 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 31 | # config.action_controller.asset_host = 'http://assets.example.com' 32 | 33 | # Specifies the header that your server uses for sending files. 34 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 35 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 36 | 37 | # Mount Action Cable outside main process or domain 38 | # config.action_cable.mount_path = nil 39 | # config.action_cable.url = 'wss://example.com/cable' 40 | # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] 41 | 42 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 43 | # config.force_ssl = true 44 | 45 | # Use the lowest log level to ensure availability of diagnostic information 46 | # when problems arise. 47 | config.log_level = :debug 48 | 49 | # Prepend all log lines with the following tags. 50 | config.log_tags = [ :request_id ] 51 | 52 | # Use a different cache store in production. 53 | # config.cache_store = :mem_cache_store 54 | 55 | # Use a real queuing backend for Active Job (and separate queues per environment) 56 | # config.active_job.queue_adapter = :resque 57 | # config.active_job.queue_name_prefix = "rails-airbnb-clone_#{Rails.env}" 58 | config.action_mailer.perform_caching = false 59 | 60 | # Ignore bad email addresses and do not raise email delivery errors. 61 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 62 | # config.action_mailer.raise_delivery_errors = false 63 | 64 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 65 | # the I18n.default_locale when a translation cannot be found). 66 | config.i18n.fallbacks = true 67 | 68 | # Send deprecation notices to registered listeners. 69 | config.active_support.deprecation = :notify 70 | 71 | # Use default logging formatter so that PID and timestamp are not suppressed. 72 | config.log_formatter = ::Logger::Formatter.new 73 | 74 | # Use a different logger for distributed setups. 75 | # require 'syslog/logger' 76 | # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') 77 | 78 | if ENV["RAILS_LOG_TO_STDOUT"].present? 79 | logger = ActiveSupport::Logger.new(STDOUT) 80 | logger.formatter = config.log_formatter 81 | config.logger = ActiveSupport::TaggedLogging.new(logger) 82 | end 83 | 84 | # Do not dump schema after migrations. 85 | config.active_record.dump_schema_after_migration = false 86 | end 87 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure public file server for tests with Cache-Control for performance. 16 | config.public_file_server.enabled = true 17 | config.public_file_server.headers = { 18 | 'Cache-Control' => 'public, max-age=3600' 19 | } 20 | 21 | # Show full error reports and disable caching. 22 | config.consider_all_requests_local = true 23 | config.action_controller.perform_caching = false 24 | 25 | # Raise exceptions instead of rendering exception templates. 26 | config.action_dispatch.show_exceptions = false 27 | 28 | # Disable request forgery protection in test environment. 29 | config.action_controller.allow_forgery_protection = false 30 | config.action_mailer.perform_caching = false 31 | 32 | # Tell Action Mailer not to deliver emails to the real world. 33 | # The :test delivery method accumulates sent emails in the 34 | # ActionMailer::Base.deliveries array. 35 | config.action_mailer.delivery_method = :test 36 | 37 | # Print deprecation notices to the stderr. 38 | config.active_support.deprecation = :stderr 39 | 40 | # Raises error for missing translations 41 | # config.action_view.raise_on_missing_translations = true 42 | end 43 | -------------------------------------------------------------------------------- /config/initializers/application_controller_renderer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # ApplicationController.renderer.defaults.merge!( 4 | # http_host: 'example.org', 5 | # https: false 6 | # ) 7 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 11 | # Rails.application.config.assets.precompile += %w( search.js ) 12 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /config/initializers/devise.rb: -------------------------------------------------------------------------------- 1 | # Use this hook to configure devise mailer, warden hooks and so forth. 2 | # Many of these configuration options can be set straight in your model. 3 | Devise.setup do |config| 4 | # The secret key used by Devise. Devise uses this key to generate 5 | # random tokens. Changing this key will render invalid all existing 6 | # confirmation, reset password and unlock tokens in the database. 7 | # Devise will use the `secret_key_base` as its `secret_key` 8 | # by default. You can change it below and use your own secret key. 9 | # config.secret_key = 'c0ef5244beeddfc74413025e08f7945cad3d6171e58719749b242e57f7de98fcca3d5edf8cd4a271e60bed51f5397cac7d8038b01de4be1354d90e198d6a00f6' 10 | 11 | # ==> Mailer Configuration 12 | # Configure the e-mail address which will be shown in Devise::Mailer, 13 | # note that it will be overwritten if you use your own mailer class 14 | # with default "from" parameter. 15 | config.mailer_sender = 'loveteam@shareabed.com' 16 | 17 | # Configure the class responsible to send e-mails. 18 | # config.mailer = 'Devise::Mailer' 19 | 20 | # Configure the parent class responsible to send e-mails. 21 | # config.parent_mailer = 'ActionMailer::Base' 22 | 23 | # ==> ORM configuration 24 | # Load and configure the ORM. Supports :active_record (default) and 25 | # :mongoid (bson_ext recommended) by default. Other ORMs may be 26 | # available as additional gems. 27 | require 'devise/orm/active_record' 28 | 29 | # ==> Configuration for any authentication mechanism 30 | # Configure which keys are used when authenticating a user. The default is 31 | # just :email. You can configure it to use [:username, :subdomain], so for 32 | # authenticating a user, both parameters are required. Remember that those 33 | # parameters are used only when authenticating and not when retrieving from 34 | # session. If you need permissions, you should implement that in a before filter. 35 | # You can also supply a hash where the value is a boolean determining whether 36 | # or not authentication should be aborted when the value is not present. 37 | # config.authentication_keys = [:email] 38 | 39 | # Configure parameters from the request object used for authentication. Each entry 40 | # given should be a request method and it will automatically be passed to the 41 | # find_for_authentication method and considered in your model lookup. For instance, 42 | # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. 43 | # The same considerations mentioned for authentication_keys also apply to request_keys. 44 | # config.request_keys = [] 45 | 46 | # Configure which authentication keys should be case-insensitive. 47 | # These keys will be downcased upon creating or modifying a user and when used 48 | # to authenticate or find a user. Default is :email. 49 | config.case_insensitive_keys = [:email] 50 | 51 | # Configure which authentication keys should have whitespace stripped. 52 | # These keys will have whitespace before and after removed upon creating or 53 | # modifying a user and when used to authenticate or find a user. Default is :email. 54 | config.strip_whitespace_keys = [:email] 55 | 56 | # Tell if authentication through request.params is enabled. True by default. 57 | # It can be set to an array that will enable params authentication only for the 58 | # given strategies, for example, `config.params_authenticatable = [:database]` will 59 | # enable it only for database (email + password) authentication. 60 | # config.params_authenticatable = true 61 | 62 | # Tell if authentication through HTTP Auth is enabled. False by default. 63 | # It can be set to an array that will enable http authentication only for the 64 | # given strategies, for example, `config.http_authenticatable = [:database]` will 65 | # enable it only for database authentication. The supported strategies are: 66 | # :database = Support basic authentication with authentication key + password 67 | # config.http_authenticatable = false 68 | 69 | # If 401 status code should be returned for AJAX requests. True by default. 70 | # config.http_authenticatable_on_xhr = true 71 | 72 | # The realm used in Http Basic Authentication. 'Application' by default. 73 | # config.http_authentication_realm = 'Application' 74 | 75 | # It will change confirmation, password recovery and other workflows 76 | # to behave the same regardless if the e-mail provided was right or wrong. 77 | # Does not affect registerable. 78 | # config.paranoid = true 79 | 80 | # By default Devise will store the user in session. You can skip storage for 81 | # particular strategies by setting this option. 82 | # Notice that if you are skipping storage for all authentication paths, you 83 | # may want to disable generating routes to Devise's sessions controller by 84 | # passing skip: :sessions to `devise_for` in your config/routes.rb 85 | config.skip_session_storage = [:http_auth] 86 | 87 | # By default, Devise cleans up the CSRF token on authentication to 88 | # avoid CSRF token fixation attacks. This means that, when using AJAX 89 | # requests for sign in and sign up, you need to get a new CSRF token 90 | # from the server. You can disable this option at your own risk. 91 | # config.clean_up_csrf_token_on_authentication = true 92 | 93 | # When false, Devise will not attempt to reload routes on eager load. 94 | # This can reduce the time taken to boot the app but if your application 95 | # requires the Devise mappings to be loaded during boot time the application 96 | # won't boot properly. 97 | # config.reload_routes = true 98 | 99 | # ==> Configuration for :database_authenticatable 100 | # For bcrypt, this is the cost for hashing the password and defaults to 11. If 101 | # using other algorithms, it sets how many times you want the password to be hashed. 102 | # 103 | # Limiting the stretches to just one in testing will increase the performance of 104 | # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use 105 | # a value less than 10 in other environments. Note that, for bcrypt (the default 106 | # algorithm), the cost increases exponentially with the number of stretches (e.g. 107 | # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation). 108 | config.stretches = Rails.env.test? ? 1 : 11 109 | 110 | # Set up a pepper to generate the hashed password. 111 | # config.pepper = '569f0c4bd0ffee1288b298dc4a7c5d68368a1f8597ac0947afafafa488183d1c23304c54757389a8f6949ec3d4a0da90322ed853b429a60d9963126bd7eb4cb8' 112 | 113 | # Send a notification email when the user's password is changed 114 | # config.send_password_change_notification = false 115 | 116 | # ==> Configuration for :confirmable 117 | # A period that the user is allowed to access the website even without 118 | # confirming their account. For instance, if set to 2.days, the user will be 119 | # able to access the website for two days without confirming their account, 120 | # access will be blocked just in the third day. Default is 0.days, meaning 121 | # the user cannot access the website without confirming their account. 122 | # config.allow_unconfirmed_access_for = 2.days 123 | 124 | # A period that the user is allowed to confirm their account before their 125 | # token becomes invalid. For example, if set to 3.days, the user can confirm 126 | # their account within 3 days after the mail was sent, but on the fourth day 127 | # their account can't be confirmed with the token any more. 128 | # Default is nil, meaning there is no restriction on how long a user can take 129 | # before confirming their account. 130 | # config.confirm_within = 3.days 131 | 132 | # If true, requires any email changes to be confirmed (exactly the same way as 133 | # initial account confirmation) to be applied. Requires additional unconfirmed_email 134 | # db field (see migrations). Until confirmed, new email is stored in 135 | # unconfirmed_email column, and copied to email column on successful confirmation. 136 | config.reconfirmable = true 137 | 138 | # Defines which key will be used when confirming an account 139 | # config.confirmation_keys = [:email] 140 | 141 | # ==> Configuration for :rememberable 142 | # The time the user will be remembered without asking for credentials again. 143 | # config.remember_for = 2.weeks 144 | 145 | # Invalidates all the remember me tokens when the user signs out. 146 | config.expire_all_remember_me_on_sign_out = true 147 | 148 | # If true, extends the user's remember period when remembered via cookie. 149 | # config.extend_remember_period = false 150 | 151 | # Options to be passed to the created cookie. For instance, you can set 152 | # secure: true in order to force SSL only cookies. 153 | # config.rememberable_options = {} 154 | 155 | # ==> Configuration for :validatable 156 | # Range for password length. 157 | config.password_length = 6..128 158 | 159 | # Email regex used to validate email formats. It simply asserts that 160 | # one (and only one) @ exists in the given string. This is mainly 161 | # to give user feedback and not to assert the e-mail validity. 162 | config.email_regexp = /\A[^@\s]+@[^@\s]+\z/ 163 | 164 | # ==> Configuration for :timeoutable 165 | # The time you want to timeout the user session without activity. After this 166 | # time the user will be asked for credentials again. Default is 30 minutes. 167 | # config.timeout_in = 30.minutes 168 | 169 | # ==> Configuration for :lockable 170 | # Defines which strategy will be used to lock an account. 171 | # :failed_attempts = Locks an account after a number of failed attempts to sign in. 172 | # :none = No lock strategy. You should handle locking by yourself. 173 | # config.lock_strategy = :failed_attempts 174 | 175 | # Defines which key will be used when locking and unlocking an account 176 | # config.unlock_keys = [:email] 177 | 178 | # Defines which strategy will be used to unlock an account. 179 | # :email = Sends an unlock link to the user email 180 | # :time = Re-enables login after a certain amount of time (see :unlock_in below) 181 | # :both = Enables both strategies 182 | # :none = No unlock strategy. You should handle unlocking by yourself. 183 | # config.unlock_strategy = :both 184 | 185 | # Number of authentication tries before locking an account if lock_strategy 186 | # is failed attempts. 187 | # config.maximum_attempts = 20 188 | 189 | # Time interval to unlock the account if :time is enabled as unlock_strategy. 190 | # config.unlock_in = 1.hour 191 | 192 | # Warn on the last attempt before the account is locked. 193 | # config.last_attempt_warning = true 194 | 195 | # ==> Configuration for :recoverable 196 | # 197 | # Defines which key will be used when recovering the password for an account 198 | # config.reset_password_keys = [:email] 199 | 200 | # Time interval you can reset your password with a reset password key. 201 | # Don't put a too small interval or your users won't have the time to 202 | # change their passwords. 203 | config.reset_password_within = 6.hours 204 | 205 | # When set to false, does not sign a user in automatically after their password is 206 | # reset. Defaults to true, so a user is signed in automatically after a reset. 207 | # config.sign_in_after_reset_password = true 208 | 209 | # ==> Configuration for :encryptable 210 | # Allow you to use another hashing or encryption algorithm besides bcrypt (default). 211 | # You can use :sha1, :sha512 or algorithms from others authentication tools as 212 | # :clearance_sha1, :authlogic_sha512 (then you should set stretches above to 20 213 | # for default behavior) and :restful_authentication_sha1 (then you should set 214 | # stretches to 10, and copy REST_AUTH_SITE_KEY to pepper). 215 | # 216 | # Require the `devise-encryptable` gem when using anything other than bcrypt 217 | # config.encryptor = :sha512 218 | 219 | # ==> Scopes configuration 220 | # Turn scoped views on. Before rendering "sessions/new", it will first check for 221 | # "users/sessions/new". It's turned off by default because it's slower if you 222 | # are using only default views. 223 | # config.scoped_views = false 224 | 225 | # Configure the default scope given to Warden. By default it's the first 226 | # devise role declared in your routes (usually :user). 227 | # config.default_scope = :user 228 | 229 | # Set this configuration to false if you want /users/sign_out to sign out 230 | # only the current scope. By default, Devise signs out all scopes. 231 | # config.sign_out_all_scopes = true 232 | 233 | # ==> Navigation configuration 234 | # Lists the formats that should be treated as navigational. Formats like 235 | # :html, should redirect to the sign in page when the user does not have 236 | # access, but formats like :xml or :json, should return 401. 237 | # 238 | # If you have any extra navigational formats, like :iphone or :mobile, you 239 | # should add them to the navigational formats lists. 240 | # 241 | # The "*/*" below is required to match Internet Explorer requests. 242 | # config.navigational_formats = ['*/*', :html] 243 | 244 | # The default HTTP method used to sign out a resource. Default is :delete. 245 | config.sign_out_via = :delete 246 | 247 | # ==> OmniAuth 248 | # Add a new OmniAuth provider. Check the wiki for more information on setting 249 | # up on your models and hooks. 250 | # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo' 251 | 252 | # ==> Warden configuration 253 | # If you want to use other strategies, that are not supported by Devise, or 254 | # change the failure app, you can configure them inside the config.warden block. 255 | # 256 | # config.warden do |manager| 257 | # manager.intercept_401 = false 258 | # manager.default_strategies(scope: :user).unshift :some_external_strategy 259 | # end 260 | 261 | # ==> Mountable engine configurations 262 | # When using Devise inside an engine, let's call it `MyEngine`, and this engine 263 | # is mountable, there are some extra configurations to be taken into account. 264 | # The following options are available, assuming the engine is mounted as: 265 | # 266 | # mount MyEngine, at: '/my_engine' 267 | # 268 | # The router that invoked `devise_for`, in the example above, would be: 269 | # config.router_name = :my_engine 270 | # 271 | # When using OmniAuth, Devise cannot automatically set OmniAuth path, 272 | # so you need to do it manually. For the users scope, it would be: 273 | # config.omniauth_path_prefix = '/my_engine/users/auth' 274 | end 275 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /config/initializers/geocoder.rb: -------------------------------------------------------------------------------- 1 | Geocoder.configure( 2 | # Geocoding options 3 | # timeout: 3, # geocoding service timeout (secs) 4 | # lookup: :google, # name of geocoding service (symbol) 5 | # language: :en, # ISO-639 language code 6 | # use_https: false, # use HTTPS for lookup requests? (if supported) 7 | # http_proxy: nil, # HTTP proxy server (user:pass@host:port) 8 | # https_proxy: nil, # HTTPS proxy server (user:pass@host:port) 9 | # api_key: nil, # API key for geocoding service 10 | # cache: nil, # cache object (must respond to #[], #[]=, and #keys) 11 | # cache_prefix: 'geocoder:', # prefix (string) to use for all cache keys 12 | 13 | # Exceptions that should not be rescued by default 14 | # (if you want to implement custom error handling); 15 | # supports SocketError and Timeout::Error 16 | # always_raise: [], 17 | 18 | # Calculation options 19 | # units: :mi, # :km for kilometers or :mi for miles 20 | # distances: :linear # :spherical or :linear 21 | 22 | 23 | :lookup => :google, 24 | :api_key => ENV['GOOGLE_API_SERVER_KEY'], 25 | :use_https => true, 26 | :units => :km 27 | # [...] 28 | ) 29 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/initializers/new_framework_defaults.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | # 3 | # This file contains migration options to ease your Rails 5.0 upgrade. 4 | # 5 | # Read the Guide for Upgrading Ruby on Rails for more info on each option. 6 | 7 | # Enable per-form CSRF tokens. Previous versions had false. 8 | Rails.application.config.action_controller.per_form_csrf_tokens = true 9 | 10 | # Enable origin-checking CSRF mitigation. Previous versions had false. 11 | Rails.application.config.action_controller.forgery_protection_origin_check = true 12 | 13 | # Make Ruby 2.4 preserve the timezone of the receiver when calling `to_time`. 14 | # Previous versions had false. 15 | ActiveSupport.to_time_preserves_timezone = true 16 | 17 | # Require `belongs_to` associations by default. Previous versions had false. 18 | Rails.application.config.active_record.belongs_to_required_by_default = true 19 | 20 | # Do not halt callback chains when a callback returns false. Previous versions had true. 21 | ActiveSupport.halt_callback_chains_on_return_false = false 22 | 23 | # Configure SSL options to enable HSTS with subdomains. Previous versions had false. 24 | Rails.application.config.ssl_options = { hsts: { subdomains: true } } 25 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_rails-airbnb-clone_session' 4 | -------------------------------------------------------------------------------- /config/initializers/simple_form.rb: -------------------------------------------------------------------------------- 1 | # Use this setup block to configure all options available in SimpleForm. 2 | SimpleForm.setup do |config| 3 | # Wrappers are used by the form builder to generate a 4 | # complete input. You can remove any component from the 5 | # wrapper, change the order or even add your own to the 6 | # stack. The options given below are used to wrap the 7 | # whole input. 8 | config.wrappers :default, class: :input, 9 | hint_class: :field_with_hint, error_class: :field_with_errors do |b| 10 | ## Extensions enabled by default 11 | # Any of these extensions can be disabled for a 12 | # given input by passing: `f.input EXTENSION_NAME => false`. 13 | # You can make any of these extensions optional by 14 | # renaming `b.use` to `b.optional`. 15 | 16 | # Determines whether to use HTML5 (:email, :url, ...) 17 | # and required attributes 18 | b.use :html5 19 | 20 | # Calculates placeholders automatically from I18n 21 | # You can also pass a string as f.input placeholder: "Placeholder" 22 | b.use :placeholder 23 | 24 | ## Optional extensions 25 | # They are disabled unless you pass `f.input EXTENSION_NAME => true` 26 | # to the input. If so, they will retrieve the values from the model 27 | # if any exists. If you want to enable any of those 28 | # extensions by default, you can change `b.optional` to `b.use`. 29 | 30 | # Calculates maxlength from length validations for string inputs 31 | # and/or database column lengths 32 | b.optional :maxlength 33 | 34 | # Calculate minlength from length validations for string inputs 35 | b.optional :minlength 36 | 37 | # Calculates pattern from format validations for string inputs 38 | b.optional :pattern 39 | 40 | # Calculates min and max from length validations for numeric inputs 41 | b.optional :min_max 42 | 43 | # Calculates readonly automatically from readonly attributes 44 | b.optional :readonly 45 | 46 | ## Inputs 47 | b.use :label_input 48 | b.use :hint, wrap_with: { tag: :span, class: :hint } 49 | b.use :error, wrap_with: { tag: :span, class: :error } 50 | 51 | ## full_messages_for 52 | # If you want to display the full error message for the attribute, you can 53 | # use the component :full_error, like: 54 | # 55 | # b.use :full_error, wrap_with: { tag: :span, class: :error } 56 | end 57 | 58 | # The default wrapper to be used by the FormBuilder. 59 | config.default_wrapper = :default 60 | 61 | # Define the way to render check boxes / radio buttons with labels. 62 | # Defaults to :nested for bootstrap config. 63 | # inline: input + label 64 | # nested: label > input 65 | config.boolean_style = :nested 66 | 67 | # Default class for buttons 68 | config.button_class = 'btn' 69 | 70 | # Method used to tidy up errors. Specify any Rails Array method. 71 | # :first lists the first message for each field. 72 | # Use :to_sentence to list all errors for each field. 73 | # config.error_method = :first 74 | 75 | # Default tag used for error notification helper. 76 | config.error_notification_tag = :div 77 | 78 | # CSS class to add for error notification helper. 79 | config.error_notification_class = 'error_notification' 80 | 81 | # ID to add for error notification helper. 82 | # config.error_notification_id = nil 83 | 84 | # Series of attempts to detect a default label method for collection. 85 | # config.collection_label_methods = [ :to_label, :name, :title, :to_s ] 86 | 87 | # Series of attempts to detect a default value method for collection. 88 | # config.collection_value_methods = [ :id, :to_s ] 89 | 90 | # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none. 91 | # config.collection_wrapper_tag = nil 92 | 93 | # You can define the class to use on all collection wrappers. Defaulting to none. 94 | # config.collection_wrapper_class = nil 95 | 96 | # You can wrap each item in a collection of radio/check boxes with a tag, 97 | # defaulting to :span. 98 | # config.item_wrapper_tag = :span 99 | 100 | # You can define a class to use in all item wrappers. Defaulting to none. 101 | # config.item_wrapper_class = nil 102 | 103 | # How the label text should be generated altogether with the required text. 104 | # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" } 105 | 106 | # You can define the class to use on all labels. Default is nil. 107 | # config.label_class = nil 108 | 109 | # You can define the default class to be used on forms. Can be overriden 110 | # with `html: { :class }`. Defaulting to none. 111 | # config.default_form_class = nil 112 | 113 | # You can define which elements should obtain additional classes 114 | # config.generate_additional_classes_for = [:wrapper, :label, :input] 115 | 116 | # Whether attributes are required by default (or not). Default is true. 117 | # config.required_by_default = true 118 | 119 | # Tell browsers whether to use the native HTML5 validations (novalidate form option). 120 | # These validations are enabled in SimpleForm's internal config but disabled by default 121 | # in this configuration, which is recommended due to some quirks from different browsers. 122 | # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations, 123 | # change this configuration to true. 124 | config.browser_validations = false 125 | 126 | # Collection of methods to detect if a file type was given. 127 | # config.file_methods = [ :mounted_as, :file?, :public_filename ] 128 | 129 | # Custom mappings for input types. This should be a hash containing a regexp 130 | # to match as key, and the input type that will be used when the field name 131 | # matches the regexp as value. 132 | # config.input_mappings = { /count/ => :integer } 133 | 134 | # Custom wrappers for input types. This should be a hash containing an input 135 | # type as key and the wrapper that will be used for all inputs with specified type. 136 | # config.wrapper_mappings = { string: :prepend } 137 | 138 | # Namespaces where SimpleForm should look for custom input classes that 139 | # override default inputs. 140 | # config.custom_inputs_namespaces << "CustomInputs" 141 | 142 | # Default priority for time_zone inputs. 143 | # config.time_zone_priority = nil 144 | 145 | # Default priority for country inputs. 146 | # config.country_priority = nil 147 | 148 | # When false, do not use translations for labels. 149 | # config.translate_labels = true 150 | 151 | # Automatically discover new inputs in Rails' autoload path. 152 | # config.inputs_discovery = true 153 | 154 | # Cache SimpleForm inputs discovery 155 | # config.cache_discovery = !Rails.env.development? 156 | 157 | # Default class for inputs 158 | # config.input_class = nil 159 | 160 | # Define the default class of the input wrapper of the boolean input. 161 | config.boolean_label_class = 'checkbox' 162 | 163 | # Defines if the default input wrapper class should be included in radio 164 | # collection wrappers. 165 | # config.include_default_input_wrapper_class = true 166 | 167 | # Defines which i18n scope will be used in Simple Form. 168 | # config.i18n_scope = 'simple_form' 169 | end 170 | -------------------------------------------------------------------------------- /config/initializers/simple_form_bootstrap.rb: -------------------------------------------------------------------------------- 1 | # Use this setup block to configure all options available in SimpleForm. 2 | SimpleForm.setup do |config| 3 | config.error_notification_class = 'alert alert-danger' 4 | config.button_class = 'btn btn-default' 5 | config.boolean_label_class = nil 6 | 7 | config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 8 | b.use :html5 9 | b.use :placeholder 10 | b.optional :maxlength 11 | b.optional :minlength 12 | b.optional :pattern 13 | b.optional :min_max 14 | b.optional :readonly 15 | b.use :label, class: 'control-label' 16 | 17 | b.use :input, class: 'form-control' 18 | b.use :error, wrap_with: { tag: 'span', class: 'help-block' } 19 | b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 20 | end 21 | 22 | config.wrappers :vertical_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 23 | b.use :html5 24 | b.use :placeholder 25 | b.optional :maxlength 26 | b.optional :minlength 27 | b.optional :readonly 28 | b.use :label, class: 'control-label' 29 | 30 | b.use :input 31 | b.use :error, wrap_with: { tag: 'span', class: 'help-block' } 32 | b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 33 | end 34 | 35 | config.wrappers :vertical_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 36 | b.use :html5 37 | b.optional :readonly 38 | 39 | b.wrapper tag: 'div', class: 'checkbox' do |ba| 40 | ba.use :label_input 41 | end 42 | 43 | b.use :error, wrap_with: { tag: 'span', class: 'help-block' } 44 | b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 45 | end 46 | 47 | config.wrappers :vertical_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 48 | b.use :html5 49 | b.optional :readonly 50 | b.use :label, class: 'control-label' 51 | b.use :input 52 | b.use :error, wrap_with: { tag: 'span', class: 'help-block' } 53 | b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 54 | end 55 | 56 | config.wrappers :horizontal_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 57 | b.use :html5 58 | b.use :placeholder 59 | b.optional :maxlength 60 | b.optional :minlength 61 | b.optional :pattern 62 | b.optional :min_max 63 | b.optional :readonly 64 | b.use :label, class: 'col-sm-3 control-label' 65 | 66 | b.wrapper tag: 'div', class: 'col-sm-9' do |ba| 67 | ba.use :input, class: 'form-control' 68 | ba.use :error, wrap_with: { tag: 'span', class: 'help-block' } 69 | ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 70 | end 71 | end 72 | 73 | config.wrappers :horizontal_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 74 | b.use :html5 75 | b.use :placeholder 76 | b.optional :maxlength 77 | b.optional :minlength 78 | b.optional :readonly 79 | b.use :label, class: 'col-sm-3 control-label' 80 | 81 | b.wrapper tag: 'div', class: 'col-sm-9' do |ba| 82 | ba.use :input 83 | ba.use :error, wrap_with: { tag: 'span', class: 'help-block' } 84 | ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 85 | end 86 | end 87 | 88 | config.wrappers :horizontal_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 89 | b.use :html5 90 | b.optional :readonly 91 | 92 | b.wrapper tag: 'div', class: 'col-sm-offset-3 col-sm-9' do |wr| 93 | wr.wrapper tag: 'div', class: 'checkbox' do |ba| 94 | ba.use :label_input 95 | end 96 | 97 | wr.use :error, wrap_with: { tag: 'span', class: 'help-block' } 98 | wr.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 99 | end 100 | end 101 | 102 | config.wrappers :horizontal_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 103 | b.use :html5 104 | b.optional :readonly 105 | 106 | b.use :label, class: 'col-sm-3 control-label' 107 | 108 | b.wrapper tag: 'div', class: 'col-sm-9' do |ba| 109 | ba.use :input 110 | ba.use :error, wrap_with: { tag: 'span', class: 'help-block' } 111 | ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 112 | end 113 | end 114 | 115 | config.wrappers :inline_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 116 | b.use :html5 117 | b.use :placeholder 118 | b.optional :maxlength 119 | b.optional :minlength 120 | b.optional :pattern 121 | b.optional :min_max 122 | b.optional :readonly 123 | b.use :label, class: 'sr-only' 124 | 125 | b.use :input, class: 'form-control' 126 | b.use :error, wrap_with: { tag: 'span', class: 'help-block' } 127 | b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 128 | end 129 | 130 | config.wrappers :multi_select, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 131 | b.use :html5 132 | b.optional :readonly 133 | b.use :label, class: 'control-label' 134 | b.wrapper tag: 'div', class: 'form-inline' do |ba| 135 | ba.use :input, class: 'form-control' 136 | ba.use :error, wrap_with: { tag: 'span', class: 'help-block' } 137 | ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 138 | end 139 | end 140 | # Wrappers for forms and inputs using the Bootstrap toolkit. 141 | # Check the Bootstrap docs (http://getbootstrap.com) 142 | # to learn about the different styles for forms and inputs, 143 | # buttons and other elements. 144 | config.default_wrapper = :vertical_form 145 | config.wrapper_mappings = { 146 | check_boxes: :vertical_radio_and_checkboxes, 147 | radio_buttons: :vertical_radio_and_checkboxes, 148 | file: :vertical_file_input, 149 | boolean: :vertical_boolean, 150 | datetime: :multi_select, 151 | date: :multi_select, 152 | time: :multi_select 153 | } 154 | end 155 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /config/locales/devise.en.yml: -------------------------------------------------------------------------------- 1 | # Additional translations at https://github.com/plataformatec/devise/wiki/I18n 2 | 3 | en: 4 | devise: 5 | confirmations: 6 | confirmed: "Your email address has been successfully confirmed." 7 | send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes." 8 | send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes." 9 | failure: 10 | already_authenticated: "You are already signed in." 11 | inactive: "Your account is not activated yet." 12 | invalid: "Invalid %{authentication_keys} or password." 13 | locked: "Your account is locked." 14 | last_attempt: "You have one more attempt before your account is locked." 15 | not_found_in_database: "Invalid %{authentication_keys} or password." 16 | timeout: "Your session expired. Please sign in again to continue." 17 | unauthenticated: "You need to sign in or sign up before continuing." 18 | unconfirmed: "You have to confirm your email address before continuing." 19 | mailer: 20 | confirmation_instructions: 21 | subject: "Confirmation instructions" 22 | reset_password_instructions: 23 | subject: "Reset password instructions" 24 | unlock_instructions: 25 | subject: "Unlock instructions" 26 | password_change: 27 | subject: "Password Changed" 28 | omniauth_callbacks: 29 | failure: "Could not authenticate you from %{kind} because \"%{reason}\"." 30 | success: "Successfully authenticated from %{kind} account." 31 | passwords: 32 | no_token: "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided." 33 | send_instructions: "You will receive an email with instructions on how to reset your password in a few minutes." 34 | send_paranoid_instructions: "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes." 35 | updated: "Your password has been changed successfully. You are now signed in." 36 | updated_not_active: "Your password has been changed successfully." 37 | registrations: 38 | destroyed: "Bye! Your account has been successfully cancelled. We hope to see you again soon." 39 | signed_up: "Welcome! You have signed up successfully." 40 | signed_up_but_inactive: "You have signed up successfully. However, we could not sign you in because your account is not yet activated." 41 | signed_up_but_locked: "You have signed up successfully. However, we could not sign you in because your account is locked." 42 | signed_up_but_unconfirmed: "A message with a confirmation link has been sent to your email address. Please follow the link to activate your account." 43 | update_needs_confirmation: "You updated your account successfully, but we need to verify your new email address. Please check your email and follow the confirm link to confirm your new email address." 44 | updated: "Your account has been updated successfully." 45 | sessions: 46 | signed_in: "Signed in successfully." 47 | signed_out: "Signed out successfully." 48 | already_signed_out: "Signed out successfully." 49 | unlocks: 50 | send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes." 51 | send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes." 52 | unlocked: "Your account has been unlocked successfully. Please sign in to continue." 53 | errors: 54 | messages: 55 | already_confirmed: "was already confirmed, please try signing in" 56 | confirmation_period_expired: "needs to be confirmed within %{period}, please request a new one" 57 | expired: "has expired, please request a new one" 58 | not_found: "not found" 59 | not_locked: "was not locked" 60 | not_saved: 61 | one: "1 error prohibited this %{resource} from being saved:" 62 | other: "%{count} errors prohibited this %{resource} from being saved:" 63 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /config/locales/simple_form.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | simple_form: 3 | "yes": 'Yes' 4 | "no": 'No' 5 | required: 6 | text: 'required' 7 | mark: '*' 8 | # You can uncomment the line below if you need to overwrite the whole required html. 9 | # When using html, text and mark won't be used. 10 | # html: '*' 11 | error_notification: 12 | default_message: "Please review the problems below:" 13 | # Examples 14 | # labels: 15 | # defaults: 16 | # password: 'Password' 17 | # user: 18 | # new: 19 | # email: 'E-mail to sign in.' 20 | # edit: 21 | # email: 'E-mail.' 22 | # hints: 23 | # defaults: 24 | # username: 'User name to sign in.' 25 | # password: 'No special characters, please.' 26 | # include_blanks: 27 | # defaults: 28 | # age: 'Rather not say' 29 | # prompts: 30 | # defaults: 31 | # age: 'Select your age' 32 | -------------------------------------------------------------------------------- /config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum, this matches the default thread size of Active Record. 6 | # 7 | threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }.to_i 8 | threads threads_count, threads_count 9 | 10 | # Specifies the `port` that Puma will listen on to receive requests, default is 3000. 11 | # 12 | port ENV.fetch("PORT") { 3000 } 13 | 14 | # Specifies the `environment` that Puma will run in. 15 | # 16 | environment ENV.fetch("RAILS_ENV") { "development" } 17 | 18 | # Specifies the number of `workers` to boot in clustered mode. 19 | # Workers are forked webserver processes. If using threads and workers together 20 | # the concurrency of the application would be max `threads` * `workers`. 21 | # Workers do not work on JRuby or Windows (both of which do not support 22 | # processes). 23 | # 24 | # workers ENV.fetch("WEB_CONCURRENCY") { 2 } 25 | 26 | # Use the `preload_app!` method when specifying a `workers` number. 27 | # This directive tells Puma to first boot the application and load code 28 | # before forking the application. This takes advantage of Copy On Write 29 | # process behavior so workers use less memory. If you use this option 30 | # you need to make sure to reconnect any threads in the `on_worker_boot` 31 | # block. 32 | # 33 | # preload_app! 34 | 35 | # The code in the `on_worker_boot` will be called if you are using 36 | # clustered mode by specifying a number of `workers`. After each worker 37 | # process is booted this block will be run, if you are using `preload_app!` 38 | # option you will want to use this block to reconnect to any threads 39 | # or connections that may have been created at application boot, Ruby 40 | # cannot share connections between processes. 41 | # 42 | # on_worker_boot do 43 | # ActiveRecord::Base.establish_connection if defined?(ActiveRecord) 44 | # end 45 | 46 | # Allow puma to be restarted by `rails restart` command. 47 | plugin :tmp_restart 48 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | root to: 'pages#home' 3 | 4 | mount Attachinary::Engine => "/attachinary" 5 | 6 | devise_for :users 7 | resources :beds do 8 | resources :bookings, only: [:create] 9 | 10 | end 11 | resources :bookings, only: [:index, :show, :destroy, :update] do 12 | resources :reviews, only: [:create, :index, :show] 13 | end 14 | 15 | namespace :my do 16 | resources :beds, only: [:index] 17 | resources :bookings, only: [:index, :update] 18 | end 19 | # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html 20 | end 21 | 22 | -------------------------------------------------------------------------------- /config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rails secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: 4cd230ef2727a63439169f334794f9c48fb352a124003dee3a8ac36c1cb9c459e2fa17be64b138f0250054c2645e838e012aae7b285223584bf89bfc7ba6ea5b 15 | 16 | test: 17 | secret_key_base: 51c1199db2edcd7a3de5cf7976097b4fbd25218b0283e8cae3bd1e348a3374f69114adaa1b87c6f19d8303a474f4d0c3fcc00359454ad921dccd1027f4cc0386 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /config/spring.rb: -------------------------------------------------------------------------------- 1 | %w( 2 | .ruby-version 3 | .rbenv-vars 4 | tmp/restart.txt 5 | tmp/caching-dev.txt 6 | config/application.yml 7 | ).each { |path| Spring.watch(path) } 8 | -------------------------------------------------------------------------------- /db/migrate/20170213145054_devise_create_users.rb: -------------------------------------------------------------------------------- 1 | class DeviseCreateUsers < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :users do |t| 4 | ## Database authenticatable 5 | t.string :email, null: false, default: "" 6 | t.string :encrypted_password, null: false, default: "" 7 | 8 | ## Recoverable 9 | t.string :reset_password_token 10 | t.datetime :reset_password_sent_at 11 | 12 | ## Rememberable 13 | t.datetime :remember_created_at 14 | 15 | ## Trackable 16 | t.integer :sign_in_count, default: 0, null: false 17 | t.datetime :current_sign_in_at 18 | t.datetime :last_sign_in_at 19 | t.inet :current_sign_in_ip 20 | t.inet :last_sign_in_ip 21 | 22 | ## Confirmable 23 | # t.string :confirmation_token 24 | # t.datetime :confirmed_at 25 | # t.datetime :confirmation_sent_at 26 | # t.string :unconfirmed_email # Only if using reconfirmable 27 | 28 | ## Lockable 29 | # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts 30 | # t.string :unlock_token # Only if unlock strategy is :email or :both 31 | # t.datetime :locked_at 32 | 33 | 34 | t.timestamps null: false 35 | end 36 | 37 | add_index :users, :email, unique: true 38 | add_index :users, :reset_password_token, unique: true 39 | # add_index :users, :confirmation_token, unique: true 40 | # add_index :users, :unlock_token, unique: true 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /db/migrate/20170213153159_add_column_to_user.rb: -------------------------------------------------------------------------------- 1 | class AddColumnToUser < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :users, :first_name, :string 4 | add_column :users, :last_name, :string 5 | add_column :users, :gender, :string 6 | add_column :users, :gender_preferences, :string 7 | add_column :users, :description, :text 8 | add_column :users, :photo, :string 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /db/migrate/20170213154859_create_beds.rb: -------------------------------------------------------------------------------- 1 | class CreateBeds < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :beds do |t| 4 | t.string :address 5 | t.string :title 6 | t.string :photo 7 | t.integer :price 8 | t.text :description 9 | t.references :user, foreign_key: true 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20170213155555_create_bookings.rb: -------------------------------------------------------------------------------- 1 | class CreateBookings < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :bookings do |t| 4 | t.date :checkin_on 5 | t.date :checkout_on 6 | t.integer :value 7 | t.string :status 8 | t.references :user, foreign_key: true 9 | t.references :bed, foreign_key: true 10 | 11 | t.timestamps 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /db/migrate/20170213172408_add_column_to_bed.rb: -------------------------------------------------------------------------------- 1 | class AddColumnToBed < ActiveRecord::Migration[5.0] 2 | def change 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /db/migrate/20170213172524_add_columns_to_bed.rb: -------------------------------------------------------------------------------- 1 | class AddColumnsToBed < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :beds, :city, :string 4 | add_column :beds, :zipcode, :string 5 | add_column :beds, :country, :string 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /db/migrate/20170214102719_create_attachinary_tables.attachinary.rb: -------------------------------------------------------------------------------- 1 | # This migration comes from attachinary (originally 20120612112526) 2 | class CreateAttachinaryTables < ActiveRecord::Migration 3 | def change 4 | create_table :attachinary_files do |t| 5 | t.references :attachinariable, polymorphic: true 6 | t.string :scope 7 | 8 | t.string :public_id 9 | t.string :version 10 | t.integer :width 11 | t.integer :height 12 | t.string :format 13 | t.string :resource_type 14 | t.timestamps 15 | end 16 | add_index :attachinary_files, [:attachinariable_type, :attachinariable_id, :scope], name: 'by_scoped_parent' 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /db/migrate/20170214110259_add_pillow_to_beds.rb: -------------------------------------------------------------------------------- 1 | class AddPillowToBeds < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :beds, :pillow, :boolean 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /db/migrate/20170214110645_add_columns_to_beds.rb: -------------------------------------------------------------------------------- 1 | class AddColumnsToBeds < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :beds, :blanket_type, :string 4 | add_column :beds, :breakfast, :boolean 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20170215102014_add_coordinates_to_beds.rb: -------------------------------------------------------------------------------- 1 | class AddCoordinatesToBeds < ActiveRecord::Migration[5.0] 2 | def change 3 | add_column :beds, :latitude, :float 4 | add_column :beds, :longitude, :float 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /db/migrate/20170216105543_create_reviews.rb: -------------------------------------------------------------------------------- 1 | class CreateReviews < ActiveRecord::Migration[5.0] 2 | def change 3 | create_table :reviews do |t| 4 | t.text :content 5 | t.integer :rating 6 | t.references :booking, foreign_key: true 7 | 8 | 9 | t.timestamps 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # Note that this schema.rb definition is the authoritative source for your 6 | # database schema. If you need to create the application database on another 7 | # system, you should be using db:schema:load, not running all the migrations 8 | # from scratch. The latter is a flawed and unsustainable approach (the more migrations 9 | # you'll amass, the slower it'll run and the greater likelihood for issues). 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema.define(version: 20170216105543) do 14 | 15 | # These are extensions that must be enabled in order to support this database 16 | enable_extension "plpgsql" 17 | 18 | create_table "attachinary_files", force: :cascade do |t| 19 | t.string "attachinariable_type" 20 | t.integer "attachinariable_id" 21 | t.string "scope" 22 | t.string "public_id" 23 | t.string "version" 24 | t.integer "width" 25 | t.integer "height" 26 | t.string "format" 27 | t.string "resource_type" 28 | t.datetime "created_at" 29 | t.datetime "updated_at" 30 | t.index ["attachinariable_type", "attachinariable_id", "scope"], name: "by_scoped_parent", using: :btree 31 | end 32 | 33 | create_table "beds", force: :cascade do |t| 34 | t.string "address" 35 | t.string "title" 36 | t.string "photo" 37 | t.integer "price" 38 | t.text "description" 39 | t.integer "user_id" 40 | t.datetime "created_at", null: false 41 | t.datetime "updated_at", null: false 42 | t.string "city" 43 | t.string "zipcode" 44 | t.string "country" 45 | t.boolean "pillow" 46 | t.string "blanket_type" 47 | t.boolean "breakfast" 48 | t.float "latitude" 49 | t.float "longitude" 50 | t.index ["user_id"], name: "index_beds_on_user_id", using: :btree 51 | end 52 | 53 | create_table "bookings", force: :cascade do |t| 54 | t.date "checkin_on" 55 | t.date "checkout_on" 56 | t.integer "value" 57 | t.string "status" 58 | t.integer "user_id" 59 | t.integer "bed_id" 60 | t.datetime "created_at", null: false 61 | t.datetime "updated_at", null: false 62 | t.index ["bed_id"], name: "index_bookings_on_bed_id", using: :btree 63 | t.index ["user_id"], name: "index_bookings_on_user_id", using: :btree 64 | end 65 | 66 | create_table "reviews", force: :cascade do |t| 67 | t.text "content" 68 | t.integer "rating" 69 | t.integer "booking_id" 70 | t.datetime "created_at", null: false 71 | t.datetime "updated_at", null: false 72 | t.index ["booking_id"], name: "index_reviews_on_booking_id", using: :btree 73 | end 74 | 75 | create_table "users", force: :cascade do |t| 76 | t.string "email", default: "", null: false 77 | t.string "encrypted_password", default: "", null: false 78 | t.string "reset_password_token" 79 | t.datetime "reset_password_sent_at" 80 | t.datetime "remember_created_at" 81 | t.integer "sign_in_count", default: 0, null: false 82 | t.datetime "current_sign_in_at" 83 | t.datetime "last_sign_in_at" 84 | t.inet "current_sign_in_ip" 85 | t.inet "last_sign_in_ip" 86 | t.datetime "created_at", null: false 87 | t.datetime "updated_at", null: false 88 | t.string "first_name" 89 | t.string "last_name" 90 | t.string "gender" 91 | t.string "gender_preferences" 92 | t.text "description" 93 | t.string "photo" 94 | t.index ["email"], name: "index_users_on_email", unique: true, using: :btree 95 | t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree 96 | end 97 | 98 | add_foreign_key "beds", "users" 99 | add_foreign_key "bookings", "beds" 100 | add_foreign_key "bookings", "users" 101 | add_foreign_key "reviews", "bookings" 102 | end 103 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }]) 7 | # Character.create(name: 'Luke', movie: movies.first) 8 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/lib/assets/.keep -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/lib/tasks/.keep -------------------------------------------------------------------------------- /lib/templates/erb/scaffold/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%%= simple_form_for(@<%= singular_table_name %>) do |f| %> 2 | <%%= f.error_notification %> 3 | 4 |
5 | <%- attributes.each do |attribute| -%> 6 | <%%= f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> %> 7 | <%- end -%> 8 |
9 | 10 |
11 | <%%= f.button :submit %> 12 |
13 | <%% end %> 14 | -------------------------------------------------------------------------------- /log/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/log/.keep -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/background-try.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/public/background-try.jpg -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/public/favicon.ico -------------------------------------------------------------------------------- /public/feet.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/public/feet.jpg -------------------------------------------------------------------------------- /public/giphy.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/public/giphy.gif -------------------------------------------------------------------------------- /public/hearts.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/public/hearts.gif -------------------------------------------------------------------------------- /public/logo-pink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/public/logo-pink.png -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/vendor/assets/javascripts/.keep -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/coralieco/rails-airbnb-clone/c4f80efa5ee839180d5f1126830c014c190e9338/vendor/assets/stylesheets/.keep --------------------------------------------------------------------------------