Let’s create a list of restaurants by creating a Rails model with restaurant name and category.
rails g model restaurant name:string category:string
I’m going to add a few restaurants to the database by going into the console.
rails c Restaurant.create(name:"Burger King", category:"Fast Food") Restaurant.create(name:"Cheese Cake Factory", category:"Family")
Let’s generate a rails controller.
rails g controller restaurants
We’ll generate the standard routes for our restaurant resource in
Rails.application.routes.draw do resources :restaurants end
Let’s add the index action to the restaurants controller and load all of the restaurants into the
@restaurants instance variable.
@restaurants is now available for use in our views.
class RestaurantsController < ApplicationController def index @restaurants = Restaurant.all end end
I’ll create an index view
views/restaurants/index.html.haml. I’ll add a simple table. Notice that I’m using Bootstrap 4 for styling but it’s completely optional.
%h1 Restaurants %table.table.table-hover %thead %tr %th Name %th Category %tbody %tr %td
We have a table but there’s nothing in it. Let’s add the list of restaurants.
%h1 Restaurants %table.table.table-hover %thead %tr %th Name %th Category %tbody - @restaurants.each do |restaurant| %tr %td = restaurant.name %td = restaurant.category
Let’s add a link to the index page to add a new restaurant.
= link_to "Add Restaurant", new_restaurant_path, class:"btn btn-primary", remote: true
Notice that I added
remote: true to the
Go ahead, try to click the button. Nothing will happen.
Ajax and responding with JS
Let’s create a
new action in the controller and load a new restaurant instance into the
@restaurant instance variable. We’re going to use this in our form.
class RestaurantsController < ApplicationController def index @restaurants = Restaurant.all end def new @restaurant = Restaurant.new end end
Instead of clicking on the
Add Restaurant button and going to a new page, we want the form to be rendered on the same page. This means that the
new action should NOT respond to html. It should instead respond to
I’m using the responders gem to define how an action in the controller should respond. One line 2 I state that the
new action should respond to js instead of html.
class RestaurantsController < ApplicationController respond_to :js, only: [:new] def index @restaurants = Restaurant.all end def new @restaurant = Restaurant.new end
Let’s return back to the add restaurant button. When you click it, watch your server console. You’ll see that Rails is trying to process the
new action as JS but it can’t find a template to use.
We solve this by creating
Refresh your page and click the add restaurants button again. The
new.js.erb file renders but it’s empty.
new.js.haml. That’s the only reason.
We want this file to display a form for us to add new restaurants.
Let’s add a form to our index page that we’ll use to add a new restaurant. I’ll use
form_with and call on a new instance of a Restaurant. I added the form right above the
link_to helper. Take note that I added an id
new-restaurant-form so that I had a way of selecting the form somehow with java script.
%h1 Restaurants %table.table.table-hover %thead %tr %th Name %th Category %tbody - @restaurants.each do |restaurant| %tr %td = restaurant.name %td = restaurant.category %div#new-restaurant-form.my-3 =form_with model: Restaurant.new do |form| = form.text_field :name, placeholder: 'Name' = form.text_field :category, placeholder: 'Category' = form.submit = link_to "Add Restaurant", new_restaurant_path, class:"btn btn-primary", remote: true
create action that will get triggered once the “create restaurant” button is clicked. Let’s also create strong parameters as a private method which helps us create the new restaurant object. In
def create @restaurant = Restaurant.new(restaurant_params) @restaurant.save end private def restaurant_params params.require(:restaurant).permit(:name, :category) end
Note that in the
create action, we’re grabbing the passed in params from the form we submitted and we’re filling out a new instance of
@restaurant. We’re then saving the restaurant object to the database.
Go to the restaurants page and enter a restaurant and click the “create restaurant” button. Nothing happens. Refresh the page manually and you’ll see your entry in the list.
First I want the form to appear when we click the add restaurant button. By default, I’m going to apply an HTML class
d-none(display: none) to hide the form by default. When the page is refreshed, the form is not visible.
When we render
new.js.erb, I want to show the form. I can do that using Jquery. Inside of
new.js.erb action is run, we select the
new-restaurant-form by id using Jquery and toggle the class to remove display: none. Refresh the page and try to press the add restaurant button. You’ll see that the form show up and disappears each time you press the button.
However, we want to see the restaurant added to the table.
Let’s dynamically add a row in our
create.js.erb file. We’re calling the
@restaurant instance variable and grabbing it’s name and category and inserting those values into the table as a row.
$('tbody').after('<tr class="child"><td><%= j(@restaurant.name) %></td><td><%= j(@restaurant.category) %></td></tr>')
Try to fill out the form now. You’ll see that the table updates automatically.