Calendar appointments app with jQuery and Haml

Linked Projects:

Calreact
 

Lesson code - https://github.com/learnetto/calreact/tree/lesson-3.1

Corrections and notes:

If you're using Rails 5.1 or higher, you will get an ActionController::InvalidAuthenticityToken error because the CSRF token will be missing.

Since version 5.1, Rails doesn't include jQuery and jquery_ujs, which automatically took care of including the CSRF token in all requests. So you can work around the issue by installing the jquery-rails gem. Place this in your Gemfile:

gem 'jquery-rails'

And run:

$ bundle install

Then require both jquery and jquery_ujs into your application.js manifest:

//= require jquery
//= require jquery_ujs

If you're using a version of Rails older than 5.1, this is already included automatically, so you don't need to do it.


In this module we are going to build our first Rails app, which is going to use React. We are going to build a calendar app for making appointments. This is what it looks like, and this is how it works.

There is a form at the top where you can enter the appointment title and the date and time. So let’s say ‘CEO Summit’ and then you can use this calendar widget to choose a date and time, and then press ‘Make Appointment’. Then you’ll see the new appointment down here. Appointments are listed in chronological order, right below the calendar. So the appointment we just made appears here.

This app involves building a few different react components, and in the end also using external React component libraries for displaying this calendar.

We are going to use the same Rails 5 app that we built in the previous lesson. If you remember, we created a basic appointments controller 

class AppointmentsController < ApplicationController
  def index
  end
end

and an index view associated with that:
<%= react_component(‘Appointments’) %>

within which we used the ‘react_component’ helper method to render the ‘Appointments’ React component, which simply displayed an h1 tag with the title of the app.

Now, before we jump in to building this as a React app, we are going to first build it just using the default Rails way using Haml template and jQuery. And then we are going to replace that code gradually with one React component at a time. This will help you see how the changes happen in going from a typical Rails setup to React. And that will also help you appreciate the changes and benefits of using React.

So let’s start by changing the index view to Haml template. You can also use Erb if you prefer; I just like Haml more.

For it to work we need to install the Haml gem:

gem ‘haml’

Then run 'bundle' to install it.

Then we need to rename the file from index.html.erb to index.html.haml.

For now, let’s remove this line:

<%= react_component(‘Appointments’) %>

And we are going to replace this with an h1 tag with the title of our app. 

%h1 React Calendar

We’ll need an appointment model, so let’s create that using Rails generator. We need a ‘title’ field of type string and an appointment time field of type datetime:

rails g model Appointment title:string appt_time:datetime

Let’s migrate the database:

rake db:migrate

That’s done. Now, in the app/models directory we should see an appointment model file:
class Appointment < ApplicationRecord
end
If we have a quick look at the finished app, we need to add more text in the form and the list of appointments. So let’s add those titles:

%h2 Appointments

%h3 Make a new appointment

And then we’re going to add a form for making appointments, and the list of appointments just below that. I am just going paste in some code here. 

= form_for @appointment do |f|
   = f.text_field :title
   = f.text_field :appt_time
   = f.submit ‘Make appointment’

- @appointments.each do |a|
   %h3= a.title
   %p= a.appt_time

We need to add appointments as a resource in the config/routes.rb file:
resources :appointments

So we have a form for appointments with a text field ‘title’ and another for ‘appt_time’, and a submit button. And then below that, we iterate through the list of the appointments, and display each of them.

Now, this data is coming from the controller, where we have defined ‘appointments’, getting all the appointments in ascending order of appointment time. And we’ve also defined ‘appointment’ as a new record:

class AppointmentsController < ApplicationController
  def index
     @appointments = Appointment.order(‘appt_time ASC’)
     @appointment = Appointment.new
  end
end
Okay, so now we can see these elements on our page.

Let’s just add a bit of css to make the page look a bit nicer:

body {
  width:500px;
  margin:auto;
  font-family: Arial, sans-serif;
  font-size: 14px;
  line-height: 1.5;
  padding-bottom: 200px;
}
Notice we are not using the interactive calender date picker widget yet. We’ll add it later on. Let’s try this:

‘Meet Joe’, ’25 January 2017 11am’
and we submit the form. We’ve got an error because we haven’t defined an action to handle the form, so let’s do that.

Let’s create a ‘create’ action in the controller. Set appointment equals Appointment.create appointment_params:

def create
  @appointment = Appointment.create(appointment_params)
end
Then we need to define that as a private method because we’re using strong parameters here. :

private
def appointment_params
  params.require(:appointment).permit(:title, :appt_time)
end

And let’s also add a redirect up here:
def create
  @appointment = Appointment.create(appointment_params)
  redirect_to :root
end

So let’s try again. ‘Meet Joe’ on ’25 January 2017 11am’. Click ‘Make appointment’. And there we go. It works now.

We don’t want the page to reload, so let’s make the form do an ajax request. Let’s add a ‘remote’ option and set that to true here:

= form_for @appointment, remote: true do |f|

By default, when we don’t pass it, it is set to ‘false’. So that will make it into an ajax request. And let’s move the list of appointments into its own partial so that when we submit the form and a new appointment is returned, we can simply update this part. 

So I’m just going to take that and make a new file and save that as ‘_appointments.html.haml’. And then back in this index file, we can just create a new div and just say render ‘appointments:

#appointments
  = render ‘appointments’

So now when we get the new appointment back from the controller, we can simply update this div. 

We need to make a file called create.js.haml file in our 'views/appointments' directory, that will handle the response of the ajax request.

We’ll take the div with the id ‘appointments’ and populate it with the new list of appointments, including our just created appointment:

:plain
   $(‘#appointments’).html(“#{escape_javascript(render ‘appointments’)}”);

Finally, we need to send the latest set of appointments in our response from the action:

def create
  @appointment = Appointment.create(appointment_params)
  @appointments = Appointment.order(‘appt_time ASC’)
end

We don’t need the redirect anymore.

Now let’s try this again. ‘CEO Summit’  and your date ‘1 March 2017 11am’ and submit, and it works without a page reload. Great!

And so to recap, we changed a few things; we added a form with the remote option set to true. And then we had to add this create.js.haml file to handle the response of the ajax request. And for that to work, we also had to get the appointments data again from the server. We’re going to do the same thing in React by replacing everything on this page, one by one, with React components.

Liked this tutorial? Get more like this in your inbox