Welcome, Guest User :: Click here to login

Logo 67272q

Lab 8: Friends

Due Date: April 16

Objectives

  • teach students how to send an email via Rails
  • teach students how to upload files to an application
  • reinforce earlier Rails development skills
  • not continually pester them about Git because they know to commit regularly by now

README.md

Part 1: Sending emails

  1. We are going to create a very simple Rails project called 'Friends' that will allow us to keep the contact information for our pals. It should have only one model called Friend. As a reminder, create the Rails app (rails new Friends) and use rails generate scaffold to create the model. In terms of attributes, a friend should have a full name (full_name), nickname, email, phone, website, and a friendship level. (Remember to run rails db:migrate after creating the scaffolding and don't forget to save your code to your git repo.) There are 4 friendship levels we will consider: 'Casual', 'Good', 'Close', 'Best'. Do not make a friendship level model; these levels should be saved as an array in the Friend model as seen below:
  FRIENDSHIP_LEVELS = [ ["Casual", "casual"], ["Good", "good"], ["Close", "close"], ["Best", "best"] ]
  1. Go to the form partial in the app/views/friends directory and make the friendship level a select list rather than a text field. Now go to the Friend model to add a series of validations. Make sure that the fields for name, email, and level are required. Using validates_format_of, make sure that the phone and email fields only take acceptable values for those attributes. (Look back at the test arrays for PATS if there is any doubt.) Finally, the friendship level must be one of the 4 levels allowed; no tampering with the select list should be tolerated. (If you are confident in your regex skills and have time, add another check that the website is valid.)

  2. In this next step, we are going to add a mailer so that our project can send an email every time we add a new friend to our list or delete one. Switch to a new git branch before going further. The first step is to set up an initializer with our SMTP settings. We will use Yahoo Mail in this example, but you can use another service such as Gmail by changing the code below to "smtp.gmail.com" and corresponding Gmail address and password. Within the config/initializers directory, add a new file called setup_mailer.rb and insert the following code:

  ActionMailer::Base.smtp_settings = {  
    :address              => "smtp.mail.yahoo.com",       
    :port                 => 587,                         
    :user_name            => "<your Yahoo email address>",  # ENV['YAHOO_ADDR']
    :password             => "<your Yahoo password>",       # ENV['YAHOO_PWD']
    :authentication       => "plain",  
    :enable_starttls_auto => true  
  }

(Note: If you were pushing this lab to a public repo, you would add your username and password as environment variables, or else they would be public to everyone!)

  1. Now we want to create a mailer we can use to handle the business of sending mail. We can create a basic mailer with the following code:
  rails generate mailer FriendMailer

This will create a new mailers directory with a new friend_mailer.rb model for us. If you haven't saved the code to git yet, do so before we start adding our own code to the mailer.

  1. In app\mailers\application_mailer, change the default from value to your full email address. In friend_mailer.rb, create two methods: new_friend_msg and remove_friend_msg. We will pass into the mailer a friend object so we will need to add that argument to each method. Below is code that I used to set up my first method:
  def new_friend_msg(friend)
    @friend = friend
    mail(:to => friend.email, :subject => "My New Friend")
 end

Adjust your code for both methods accordingly.

  1. Now we need to create templates that these methods can call to generate an email body. Going to the views directory, we see there is a subdirectory for friend_mailer; add two files: new_friend_msg.text.erb (for a regular text email) and remove_friend_msg.html.erb (for html-formatted email). We need to be sure to pass in the name of our friend and display it using erb tags. An example of appropriate templates can be found at the end of the lab; you will want to modify the actual text so that it sounds like it is from you. (... unless you are also half-Klingon like me, in which case the example templates will work just fine.)

  2. Finally, we have to actually send the mail. There are several ways of doing this, but we will use the most direct. Go into the friends_controller.rb file and look at the create method. After the new friend is created (if @friend.save) add the following code:

  # Provide an email confirmation if all is good...
  FriendMailer.new_friend_msg(@friend).deliver

  # Now a page confirmation as well...
  flash[:notice] = "#{@friend.nickname} has been added as a friend and notified by email."

The deliver method will call the new_friend_msg in the FriendMailer model and use the template (having the same name) to send an email to this friend. Do something similar for the delete method so that a remove_friend_msg is sent when the friend is deleted.

  1. Now time for a little testing. Start up the server (if it's already running you need to restart to get the initializer file to be included) and add a new friend, but be sure to use your email. (Please do not spam anyone during this lab.) Look at the server output (same window as rails server is running in) to see the email was sent. Now delete that friend and verify the person was notified as well. (Note: If you are using Gmail, you may not see emails in your inbox due to Google's security settings blocking access. An alternative way of displaying the email generation is presented in the next step).

  2. You may have noticed that your email did not send ... oh dear. In order to remedy this, we will use the letter opener gem to save our emails to our app locally. First, add the gem to your development environment and run the bundle command to install it.

   gem "letter_opener"

Then set the delivery method in config/environments/development.rb to

  config.action_mailer.delivery_method = :letter_opener

Now any email will pop up in your browser instead of being sent. The messages are stored in tmp/letter_opener.

Now, after confirming email generation by checking your inbox or your browser, merge all this back to the master branch.

Part 2: Uploading files

  1. Now we want to be able to add a photo of our friends so that when we display their listing, a magnificent image appears. Start by cutting a new branch in git called 'photos'. To do the uploads we will use a gem known as CarrierWave. There are other gems that can also be used – paperclip being one of the more popular ones – but carrierwave is easier to set up (IMHO) and works with ActiveRecord, DataMapper and a variety of ORMs. To get this gem installed, go to the Gemfile and type gem 'carrierwave' and then bundle install to add it to your system gems.

  2. Once the plugin is installed, we can run its generator to add a photo attribute to the Friend model with the following line of code:

  rails generate uploader photo

This creates a new directory within app called uploaders and a file within that called 'photo_uploader.rb' which will handle the logic of uploading a file. Open that file and you will see there are a lot of options commented out for us. We will leave most of these alone right now (feel free to experiment later), but there is one option we want to uncomment: the extension_white_list function. (starts around line 38 or so) This will ensure that the files being uploaded are images; to allow any type of file to be uploaded is a huge security risk and checking the extension types is the least we can do to stop potential abuse of this functionality.

  1. The uploader file will not be of much value unless we explicitly connect it to the Friends model and alter the database to record the file path. First, go into the Friend model and add near the top of the Friend class the following:
  mount_uploader :photo, PhotoUploader

Once the uploader is associated with the Friend model, we will need a migration so the connection can be recorded. On the command line, type the following:

  rails generate migration add_photo_to_friends photo:string

Open up this migration and look at the fields that are being created by this operation. Run rails db:migrate to modify the database.

  1. Make sure this parameter can be passed along by the controller to the model. Go to the friend_params method in the controller and add :photo to the list of permitted parameters.

  2. Now we have to go into the friend form partial and add a field that will allow a user to upload the image. To start, at the top of the form after the local: true, add multipart: true so that the form is capable of receiving attachments. Then go do into the form itself and add the following:

  <div class="field">
    <%= form.label :photo %><br />
    <%= form.file_field :photo %>
  </div>

This will create file upload control that will allow users to browse and select a photo to upload.

  1. To display a photo that is uploaded, go to the 'show' page for friends and add this code somewhere on the page where it is appropriate:
  <% unless @friend.photo_url.nil? %>
    <p><%= image_tag @friend.photo_url %></p>
  <% end %>
  1. Once this in place, fire up the dev server using rails server again and add a photo for your friends. You can google some sample pics (make sure it is not copyrighted). (Warning: if you use these pictures, be sure to make Darth Vader your friend. Trust me, you don't want to hack off the Dark Lord of the Sith.) Make sure you save to git and merge back to the master branch.

Template Samples

Example of new_friend_msg template:

  Dear <%= @friend.nickname %>,

  <p>I've just listed you as one of my friends.</p>
  <p>I am sure you are deeply honored, as you should be.</p>

<p> Best regards,</p>
 <p>Your new friend</p>

Example of remove_friend_msg template:

<p>Hi <%= @friend.full_name %>,</p>
<p>I had previously listed you as a friend. 
<p>Clearly it was a mistake to make you a friend.  I admit this error in judgment and hereby remove you from my friend list.</p>
<p>Regards</p>

Submission

Bonus:5 points: If you turn up your submission 48 hours before the deadline.

Your lab will be turned in via canvas as a zipped folder and git hub private remote URL -- at 11:59 pm on April 16, 2020. The private GitHub URL should be shared with Prof. Houda [username: ladyhodhod] and Preetha [username: preethagopinath]. We will access your Lab 8 solution from this GitHub repository.

Instructions on adding us as a collaborator in Github: https://help.github.com/en/github/setting-up-and-managing-your-github-user-account/inviting-collaborators-to-a-personal-repository