Skip to content

TimingJL/recipe_box

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Learning by Doing

Ubuntu version Rails version Ruby version

Mackenzie Child's video really inspired me. So I decided to follow all of his rails video tutorial to learn how to build a web app. Through the video, I would try to build the web app by my self and record the courses step by step in text to facilitate the review.

image

Project 3: How To Build A Recipe Box With Rails

This time, we're going to build a Recipe Box. We're able to add recipes and users, as well as authentication. So only sign-in users are able to edit and destroy the recipe. If we click a recipes box on the root of this application, we can see image, title, description, multiple ingredients, and multiple directions on the show page. So we have a recipe model, an ingredients model, and an directions model. And then when we create a new recipe, we can upload our image. And we can add or remove multiple ingredients and can add or remove multiple direction step.

https://mackenziechild.me/12-in-12/3/

image image image

Highlights of this course

  1. Users
  2. Posts (Recipes)
  3. Nested Forms
  4. Image Uploading
  5. HAML

Create a Recipe Box

$ rails new recipe_box

Chage directory to the recipe_box. Under recipe_box/Gemfile, add gem 'therubyracer', save and run bundle install.

Note: Because there is no Javascript interpreter for Rails on Ubuntu Operation System, we have to install Node.js or therubyracer to get the Javascript interpreter.

$ bundle install

Then run the rails server and go to http://localhost:3000 to make sure everything is correct.

Before we do anything, we do Git initialize:

$ git init
$ git add .
$ git commit -am 'Initial Commit'

Using HAML

Instead of doing anything, I'll going to use HAML. To do this, we have to install it through the gem.

Note:
Haml (HTML Abstraction Markup Language) is a markup language 
that’s used to cleanly and simply describe the HTML of any web document, without the use of inline code. 
Once it’s installed, all view files with the ".html.haml" extension will be compiled using Haml. 
Haml supports Rails’ XSS protection scheme.

Under recipe_box/Gemfile, add gem 'haml', '~>4.0.5', save and run bundle install. Then restart the server.

To get start it, let's go ahead and create a recipes

$ rails g controller recipes

In addition to our controller, we're gonna to need some routes. Under app/config/routes.rb

Rails.application.routes.draw do
  resources :recipes

  root "recipes#index"
end

So back in our recipes controller, let's create a index action Under app/controllers/recipes_controller.rb

class RecipesController < ApplicationController
	def index
	end
end

Then under our views, we're obviously need a view for a index Under app/views/recipes, we new a file named index.html.haml

%h1 This is the placeholder for the recipes#index

Create a new recipe

Let's go ahead and create the ability to add our new recipes and show our recipes.

Under app/controllers/recipes_controller.rb

class RecipesController < ApplicationController
	def index
	end

	def show
	end

	def new
	end

	def create
	end
end

I know each of the action we're gonna need to find the recipe, so I'm gonna to create a private method to hold that. And then I'm going to create a before action so that I can avoid the repeated code in each action.

Under app/controllers/recipes_controller.rb

class RecipesController < ApplicationController
	before_action :find_recipe, only: [:show, :edit, :update, :destroy]
	...
	...

	private

	def find_recipe
		@recipe = Recipe.find(params[:id])
	end
end

Under our new action and create action, we're gonna want to do:

Under app/controllers/recipes_controller.rb

class RecipesController < ApplicationController
	before_action :find_recipe, only: [:show, :edit, :update, :destroy]

	def index
	end

	def show
	end

	def new
		@recipe = Recipe.new
	end

	def create
		@recipe = Recipe.new(recipe_params)

		if @recipe.save
			redirect_to @recipe, notice: "Successfully created new recipe"
		else
			render 'new'
		end
	end

	private

	def recipe_params
		params.require(:recipe).permit(:title, :description)
	end

	def find_recipe
		@recipe = Recipe.find(params[:id])
	end
end

Then we need to create our model.

$ rails g model Recipe title:string description:text user_id:integer
$ rake db:migrate

Then let's go ahead to create the template Under app/views/recipes, we new a file named new.html.haml, and the other is going to be _form.html.haml In the app/views/recipes/_form.html.haml, we're going to use simple_form
https://github.com/plataformatec/simple_form

Before that, we need to add simple_form in our Gemfile

gem 'simple_form'
Note:      
The " gem 'simple-form' " Mackenzie used in Rails4 will get error(undefined method 'number?') in Rails5,
So I change it to :

gem 'simple_form', github: 'kesha-antonov/simple_form', branch: 'rails-5-0'

and run bundle install, then restart the server.

So we're going to use simple_form

Under app/views/recipes/_form.html.haml

= simple_form_for @recipe, html: { multipart: true } do |f|
	- if @recipe.errors.any?
		#errors
			%p
				= @recipe.errors.count
				Prevented this recipe froms saving
			%ul
				- @recipe.errors.full_messages.each do |msg|
					%li= msg
	.panel-body
		= f.input :title, input_html: { class: 'form-control' }
		= f.input :description, input_html: { class: 'form-control' }

	= f.button :submit, class: "btn btn-primary"

Then in our new.html.haml file, we're gonna do app/views/recipes/new.html.haml

%h1 New Recipe

= render 'form'

%br/

= link_to "Back", root_path, class: "btn btn-default"

Then refresh the browser and go into http://localhost:3000/recipes/new, you will see
image

And we have to create a show page to show our recipe post.

Under app/views/recipes, we new a file named show.html.haml
And list out the title and description

%h1= @recipe.title
%p= @recipe.description

=link_to "Back", root_path, class: "btn btn-default"

Note: %p= @recipe.description is unable to do text wraps, so I tweak the code to %p= simple_format @recipe.description.

%h1= @recipe.title
%p= simple_format @recipe.description

=link_to "Back", root_path, class: "btn btn-default"

In our app/controllers/recipes_controller.rb, we want to list our all of our recipes.

def index
	@recipe = Recipe.all.order("created_at DESC")
end

Now, inside of our app/views/recipes/index.html.haml, let's create a loop. So the loop list out each of our recipes.

- @recipe.each do |recipe|
	%h2= link_to recipe.title, recipe

So we have the ability to create a post. And then we'll add the ability to add and destroy as well.

Ability to Destroy posts

Under app/controllers/recipes_controller.rb

class RecipesController < ApplicationController
	before_action :find_recipe, only: [:show, :edit, :update, :destroy]

	...
	...

	def edit
	end

	def update
		if @recipe.update(recipe_params)
			redirect_to @recipe
		else
			render 'edit'
		end
	end

	def destroy
		@recipe.destroy
		redirect_to root_path, notice: "Successfully delted recipe"
	end	

	private

	def recipe_params
		params.require(:recipe).permit(:title, :description)
	end

	def find_recipe
		@recipe = Recipe.find(params[:id])
	end
end

In edit we don't need to do anything, because in before action it find recipe for us.

Then, let's create a edit.html.haml page under app/views/recipes
Under app/views/recipes/edit.html.haml

%h1 Edit Recipe

= render 'form'

Then back to our show.html.haml, let's add a edit link and a destroy link
In app/views/recipes/show.html.haml

%h1= @recipe.title
%p= simple_format @recipe.description

=link_to "Back", root_path, class: "btn btn-default"
=link_to "Edit", edit_recipe_path, class: "btn btn-default"
=link_to "Delete", recipe_path, method: :delete, data: {confirm: "Are you sure?"}, class: "btn btn-default"

So we got the basic functionality of our Recipe. image

Styling Using Bootstrap

Let's add some bootstrap.

We need to add bootstrap gem in our Gemfile, run bundle install and restart server.

gem 'bootstrap-sass', '~> 3.2.0.2'
Note:
File to import not found or unreadable: 
bootstrap-sprockets Only for Twitter Bootstrap 3, bootstrap-sprockets is used.

And if you go to the github page of the bootstrap-sass, it would give you some information on what you need to do. https://github.com/twbs/bootstrap-sass

First, we need to go into app/assets/stylesheets and rename application.css to application.css.scss.
And then, we gonna to import Bootstrap styles in app/assets/stylesheets/application.css.scss:

@import "bootstrap-sprockets";
@import "bootstrap";

image

Add some structure

Before anything, we rename app/views/layouts/application.html.erb to app/views/layouts/application.html.haml.
And change html code to haml code:

!!! 5
%html
%head
	%title RecipeBox
	= csrf_meta_tags
	= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
	= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
%body
	= yield

Let's add some structure to our applicaiton.

Navbar

First, I'm going to add Navbar.
Under app/views/layouts/application.html.haml

!!! 5
%html
%head
	%title RecipeBox
	= csrf_meta_tags
	= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
	= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
%body
	%nav.navbar.navbar-default
		.container
			.navbar-brand= link_to "Recipe Box", root_path

			%ul.nav.navbar-nav.navbar-right
				%li= link_to "New Recipe", new_recipe_path
				%li= link_to "Sign Out", root_path

	.container
		- flash.each do |name, msg|
			= content_tag :div, msg, class: "alert"

		= yield

image

Add images

Let's go ahead and add images to the recipes.

To do that, we're going to use paperclip gem.
https://github.com/thoughtbot/paperclip

We need to add paperclip gem in our Gemfile, run bundle install and restart server.
In Gemfile, we add

gem 'paperclip', '~> 4.2.0'

In our recipe model app/models/recipe.rb (Ref: Quick Start of Github paperclip)

class Recipe < ApplicationRecord
	has_attached_file :image, styles: { medium: "400x400#" }
	validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
end

Next, we need to add migration

$ rails g paperclip recipe image
$ rake db:migrate

Next, we need to add this to our form.
So in app/views/recipes/_form.html.haml

...
...
	.panel-body
		= f.input :title, input_html: { class: 'form-control' }
		= f.input :description, input_html: { class: 'form-control' }
		= f.input :image, input_html: { class: 'form-control' }
...
...

And in our recipes controller app/controllers/recipes_controller.rb, we need to add that to our recipe params.

...
...
def recipe_params
	params.require(:recipe).permit(:title, :description, :image)
end
...
...

In app/views/recipes/show.html.haml

= image_tag @recipe.image.url(:medium, class: "recipe_image")
%h1= @recipe.title
%p= simple_format @recipe.description

=link_to "Back", root_path, class: "btn btn-default"
=link_to "Edit", edit_recipe_path, class: "btn btn-default"
=link_to "Delete", recipe_path, method: :delete, data: {confirm: "Are you sure?"}, class: "btn btn-default"

Then, restart the server and refresh the browser. image

image

And then, we want to add that in our app/views/recipes/index.html.haml as well. For each recipe, we want the image tag, and this would be the link as well.

- @recipe.each do |recipe|
	= link_to recipe do
		= image_tag recipe.image.url(:medium)
	%h2= link_to recipe.title, recipe

It works well, but it looks not very well. So let's add some structure to our index page. To do this with bootstrap, we need to use the each slice method. Under app/views/recipes/index.html.haml

- @recipe.each_slice(3) do |recipes|
	.row
		- recipes.each do |recipe|
			.col-md-4
				.recipe
					.image_wrapper
						= link_to recipe do
							= image_tag recipe.image.url(:medium)
					%h2= link_to recipe.title, recipe

image

Styling

Under app/assets/stylesheets/application.css.scss

/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
 * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any styles
 * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
 * file per style scope.
 *
 *= require_tree .
 *= require_self
 */

@import "bootstrap-sprockets";
@import "bootstrap";

@mixin box-shadow {
	-webkit-box-shadow: rgba(0, 0, 0, 0.09) 0 2px 0;
	-moz-box-shadow: rgba(0, 0, 0, 0.09) 0 2px 0;
	box-shadow: rgba(0, 0, 0, 0.09) 0 2px 0;
}

$red: #DB6161;

body {
	background: rgb(235, 238, 243);
}

.main_content {
	padding: 0 0 50px 0;
}

.alert {
	padding: 15px;
	margin-bottom: 20px;
	border: 1px solid transparent;
	border-radius: 5px;
	@include box-shadow;
	background: white;
	font-weight: bold;
}

.navbar {
	margin-bottom: 50px;
	@include box-shadow;
	border: none;
	.navbar-brand {
		text-transform: uppercase;
		letter-spacing: -1px;
		font-weight: bold;
		font-size: 25px;
		a {
			color: $red;
		}
	}
}

.recipe {
	background: white;
	border-radius: 5px;
	margin-bottom: 40px;
	@include box-shadow;
	.image_wrapper {
		max-width: 100%;
		border-radius: 5px 5px 0 0;
		overflow: hidden;
	}
	img {
		width: 100%;
		-webkit-transition: all .3s ease-out;
	  -moz-transition: all .3s ease-out;
	  -o-transition: all .3s ease-out;
    transition: all .3s ease-out;
		&:hover {
			transform: scale(1.075);
		}
	}
	h2 {
		padding: 15px 5%;
		margin: 0;
		font-size: 20px;
		font-weight: normal;
		line-height: 1.5;
		a {
			color: $red;
		}
	}
}

#recipe_top {
	margin-bottom: 50px;
}

#recipe_info, #ingredients, #directions {
	background: white;
	@include box-shadow;
	min-height: 360px;
	border-radius: 5px;
	padding: 2em 8%;
}

.recipe_image {
	max-width: 100%;
	border-radius: 5px;
	@include box-shadow;
}

#recipe_info {
	h1 {
		font-size: 36px;
		font-weight: normal;
		color: $red;
	}
	.description {
		color: #8A8A8A;
		font-size: 20px;
	}
}

#ingredients, #directions {
	margin-bottom: 50px;
	ul, ol {
		padding-left: 18px;
		li {
			padding: 1em 0;
			border-bottom: 1px solid #EAEAEA;
		}
	}
}

.form-inline {
	margin-top: 15px;
}
.form-input {
	width: 65% !important;
	float: left;
}
.form-button {
	float: left;
	width: 30% !important;
	margin-left: 5%;
}
.add-button {
	margin-top: 25px;
}

Refresh the browser, and then you will see image

Add Ingredients and Directions

So next, we need to add the ability to have Ingredients and Directions for each one of our recipes. The way we gonna to do is by using gem 'cacoon'. Cacoon make it easy to have the nested form. https://github.com/nathanvda/cocoon

In Gemfile

gem 'cocoon', '~> 1.2.6'

Run bundle install and restart the server.

In app/javascripts/application.js, we add //= require cocoon under //= require jquery_ujs

//= require jquery
//= require jquery_ujs
//= require cocoon
//= require turbolinks
//= require_tree .

First, we need to create a model for our ingredients, and then the model for the directions.

$ rails g model Ingredient name:string recipe:belongs_to
$ rails g model Direction step:text recipe:belongs_to
$ rake db:migrate

And it created the Ingredient table and Direction table.

Then under recipe model, app/models/recipe.rb

class Recipe < ApplicationRecord
	has_many :ingredients
	has_many :directions


	accepts_nested_attributes_for :ingredients,
								reject_if: proc { |attributes| attributes['name'].blank? },
								allow_destroy: true
 	accepts_nested_attributes_for :directions,
								reject_if: proc { |attributes| attributes['step'].blank? },
								allow_destroy: true

	validates :title, :description, :image, presence: true

	has_attached_file :image, styles: { medium: "400x400#" }
	validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
end

And then we need to add attribute to our strong parameters insdie of our controller.
In app/controllers/recipes_controller.rb

...
...

def recipe_params
	params.require(:recipe).permit(:title, :description, :image, ingredients_attributes: [:id, :name, :_destroy], directions_attributes: [:id, :step, :_destroy])
end

...
...

Under app/views/recipes/_form.html.haml

= simple_form_for @recipe, html: { multipart: true } do |f|
	- if @recipe.errors.any?
		#errors
			%p
				= @recipe.errors.count
				Prevented this recipe froms saving
			%ul
				- @recipe.errors.full_messages.each do |msg|
					%li= msg
	.panel-body
		= f.input :title, input_html: { class: 'form-control' }
		= f.input :description, input_html: { class: 'form-control' }
		= f.input :image, input_html: { class: 'form-control' }

		.row
			.col-md-6
				%h3 Ingredients
				#ingredients
					= f.simple_fields_for :ingredients do |ingredient|
						= render 'ingredient_fields', f: ingredient
					.links
						= link_to_add_association 'Add Ingredient', f, :ingredients, class: "btn btn-default add-button"		

	= f.button :submit, class: "btn btn-primary"

Then, we need to create a partial that named _ingredient_fields.html.haml.
Under app/views/recipes/_ingredient_fields.html.haml

.form-inline.clearfix
	.nested-fields
		= f.input :name, input_html: { class: 'form-input form-control' }
		= link_to_remove_association "Remove", f, class: "form-button btn btn-default"

image

Let's go ahead to add the form for directions Under app/views/recipes/_form.html.haml

= simple_form_for @recipe, html: { multipart: true } do |f|
	- if @recipe.errors.any?
		#errors
			%p
				= @recipe.errors.count
				Prevented this recipe froms saving
			%ul
				- @recipe.errors.full_messages.each do |msg|
					%li= msg
	.panel-body
		= f.input :title, input_html: { class: 'form-control' }
		= f.input :description, input_html: { class: 'form-control' }
		= f.input :image, input_html: { class: 'form-control' }

		.row
			.col-md-6
				%h3 Ingredients
				#ingredients
					= f.simple_fields_for :ingredients do |ingredient|
						= render 'ingredient_fields', f: ingredient
					.links
						= link_to_add_association 'Add Ingredient', f, :ingredients, class: "btn btn-default add-button"						

			.col-md-6
				%h3 Directions
				#directions
					= f.simple_fields_for :directions do |direction|
						= render 'direction_fields', f: direction
					.links
						= link_to_add_association 'Add Step', f, :directions, class: "btn btn-default add-button"
						
	= f.button :submit, class: "btn btn-primary"

Then let's go ahead to create a file called _direction_fields.html.haml Under app/views/recipes/_direction_fields.html.haml

.form-inline.clearfix
	.nested-fields
		= f.input :step, input_html: { class: 'form-input form-control' }
		= link_to_remove_association "Remove Step", f, class: "btn btn-default form-button"

image

In our show file, under app/views/recipes/show.html.haml

.main_content
	#recipe_top.row
		.col-md-4
			= image_tag @recipe.image.url(:medium), class: "recipe_image"
		.col-md-8
			#recipe_info
				%h1= @recipe.title
				%p.description= @recipe.description

	.row
		.col-md-6
			#ingredients
				%h2 Ingredients
				%ul
					- @recipe.ingredients.each do |ingredient|
						%li= ingredient.name

		.col-md-6
			#directions
				%h2 Directions
				%ul
					- @recipe.directions.each do |direction|
						%li= direction.step

	.row
		.col-md-12
			= link_to "Back", root_path, class: "btn btn-default"
			= link_to "Edit", edit_recipe_path, class: "btn btn-default"
			= link_to "Delete", recipe_path, method: :delete, data: {confirm: "Are you sure?" }, class: "btn btn-default"

image

Add Users and Authentication

https://github.com/plataformatec/devise

We can add it to your Gemfile with:

	gem 'devise'

Run the bundle command to install it.

Next, we need to run the generator:

$ rails generate devise:install
Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

We'll need to set up the default URL options for the Devise mailer in each environment.
Here is a possible configuration for config/environments/development.rb:

config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

And then we copy Devise views by the command:

$ rails g devise:views

Then we must run generate to create model for our users.

$ rails g devise User

In our model app/models/user.rb

class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

  has_many :recipes
end

And then in our model app/models/recipe.rb

class Recipe < ApplicationRecord
	belongs_to :user

	...
	...
end

And run migration

$ rake db:migrate

In http://localhost:3000/users/sign_up, we have the ability to sign_up now.

Then we're going to rails console now

$ rails c

Let's do

> @recipe = Recipe.last

We found that user_id: nil Let's fix that by opening our recipes_controller.rb We gonna to tweak the way we create the recipe. Under app/controllers/recipes_controller.rb

class RecipesController < ApplicationController
...
...
	def new
		@recipe = current_user.recipes.build
	end

	def create
		@recipe = current_user.recipes.build(recipe_params)

		if @recipe.save
			redirect_to @recipe, notice: "Successfully created new recipe"
		else
			render 'new'
		end
	end
...
...

Then we create a new recipe, and do

> @recipe = Recipe.last

We can see the user_id is '1'. That's means the new recipe is assigned to a current user.

So now, in our show page app/views/recipes/show.html.haml, we can do

.main_content
	#recipe_top.row
		.col-md-4
			= image_tag @recipe.image.url(:medium), class: "recipe_image"
		.col-md-8
			#recipe_info
				%h1= @recipe.title
				%p.description= @recipe.description
				%p
					Submitted by
					= @recipe.user.email
	...
	...
	...

Authentication

In our app/controllers/recipes_controllers.rb, we want to make sure to authenticate. So let's add an before_action

class RecipesController < ApplicationController
	before_action :find_recipe, only: [:show, :edit, :update, :destroy]
	before_action :authenticate_user!, except: [:index, :show]
	...
	...

So now, if we attenpt to new recipes without login, it would go to the login page.

And then we tweak the sign_in, sign_out, and sign_up link. In app/views/layouts/application.html.haml

!!! 5
%html
%head
	%title RecipeBox
	= csrf_meta_tags
	= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload'
	= javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
%body
	%nav.navbar.navbar-default
		.container
			.navbar-brand= link_to "Recipe Box", root_path

			- if user_signed_in?
				%ul.nav.navbar-nav.navbar-right
					%li= link_to "New Recipe", new_recipe_path
					%li= link_to "Sign Out", destroy_user_session_path, method: :delete
			- else
				%ul.nav.navbar-nav.navbar-right
					%li= link_to "Sign Up", new_user_registration_path
					%li= link_to "Sign In", new_user_session_path

	.container
		- flash.each do |name, msg|
			= content_tag :div, msg, class: "alert"

		= yield

And then we hope the edit and destroy button only show up when ther user sign-in. In app/views/recipes/show.html.haml

...
...
...
	.row
		.col-md-12
			= link_to "Back", root_path, class: "btn btn-default"
			- if user_signed_in?
				= link_to "Edit", edit_recipe_path, class: "btn btn-default"
				= link_to "Delete", recipe_path, method: :delete, data: {confirm: "Are you sure?" }, class: "btn btn-default"

Styling the SignIn, SignOut, and SignUp Page.

Under app/views/devise/sessions/new.html.erb

	<div class="row">
		<div class="col-md-6 col-md-offset-3">
			<h2>Sign in</h2>

			<%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
			  <div class="form-inputs">
			    <%= f.input :email, required: false, autofocus: true, input_html: { class: 'form-control' } %>
			    <%= f.input :password, required: false, input_html: { class: 'form-control' } %>
			    <%= f.input :remember_me, as: :boolean, input_html: { class: 'form-control' } if devise_mapping.rememberable? %>
			  </div>

			  <div class="form-actions">
			    <%= f.button :submit, "Sign in", class: 'btn btn-primary' %>
			  </div>
			  <br>
			<% end %>

			<%= render "devise/shared/links" %>
		</div>
	</div>

Under app/views/devise/registrations/new.html.erb

	<div class="row">
		<div class="col-md-6 col-md-offset-3">
			<h2>Sign up</h2>

			<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
			  <%= f.error_notification %>

			  <div class="form-inputs">
			    <%= f.input :email, required: true, autofocus: true, input_html: { class: 'form-control' } %>
			    <%= f.input :password, required: true, input_html: { class: 'form-control' } %>
			    <%= f.input :password_confirmation, required: true, input_html: { class: 'form-control' } %>
			  </div>
				<br>
			  <div class="form-actions">
			    <%= f.button :submit, "Sign up", class: "btn btn-primary" %>
			  </div>
			  <br>
			<% end %>

			<%= render "devise/shared/links" %>
		</div>
	</div>

image

The RecipeBox we built is finished!

About

How To Build A Recipe Box With Rails

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published