I Deployed My Sinatra App To Heroku

MY SINATRA PORTFOLIO PROJECT IS DONE!!!

You can say I’m pretty stoked. This blog is part of the requirements though so get ready :-). Actually, I didn’t take enough notes to really get into the code in this blog. I did hit some solid stumbling blocks and there is some major refactoring of code needing to happen but I’m overall pretty happy. A large part of the time I spent was making the app look good utilizing Bootstrap.

Something that definitely needs to be refactored is one of my helper methods:

def current_user_parents
  parents = []
  current_user(session).houses.each do |house|
    Parent.where(house_id: house.id).each do |parent|
      parents << parent
    end
  end
  parents
end

It’s sandwich code (starts with a variable set to an empty array, fills that array, returns that array) so I know I can most likely eliminate two lines from that or even three if I’m not pushing onto that parents variable anymore. We’ll see. I’m interested to pick the brain of the instructor that goes over the project with me.

You can see what I’ll call v0.8 (I figure it’s close to v1.0 but not yet lol) at https://your-neighbors.herokuapp.com/. I feel like the code is solid but still some functionality and visual things that need to be resolved.

  • I’d like to add a static footer to the site.
  • If a house is deleted the parent and children remain in the database but can never be accessed again because of how I list them in relation to the house they’re in.
  • When there are no parents or children I need to add a link suggesting to create some.
  • When a user tries to access the info for something they didn’t create (ie. they created house 8 but try and go to the link for house 5) the error page tells them to log in even though they are logged in. I need to create a different error page for logged in users trying to access stuff that isn’t there’s vs. the error page when a person isn’t logged in.
  • Add some color!

I’m sure I could find more. Feel free to check out the app. Sign up, use it, and report issues to the GitHub link at the top right on every page of the application.

It was interesting deploying to Heroku as well. There isn’t a solid guide on deploying a Sinatra app with a DB to Heroku. Through Heroku’s docs and this Get Started with Sinatra on Heroku from 2013, I got it up and running though. The biggest thing was setting up Postgres and what to put in the Procfile. Let me see if I can remember what exactly I did:

  1. Add gem 'pg' to your Gemfile. Also, define your version of ruby, ie. ruby '2.4.1' in your Gemfile.
  2. I changed the sqlite gem to development like this gem 'sqlite3', :group => :development.
  3. I added a config/database.yml because the Heroku docs said to but I don’t know if it’s needed. I’ll probably delete it and see what happens in the near future. The Heroku docs have an example that I used and just changed the database: names.
  4. I think config/environment.rb is where the magic happened. I kept the :development environment using sqlite3 because I read in some of the docs that you needed to know the host, username, password, port and something else to make it work locally. I figured if I could get it to work without figuring that out I would do that. I got this working locally running shotgun and on the Heroku server too. With the changes it now looks like this:
    require 'bundler/setup'
    Bundler.require
    
    configure :development do
      ENV['SINATRA_ENV'] ||= "development"
    
      ActiveRecord::Base.establish_connection(
        :adapter => "sqlite3",
        :database => "db/neighborhood#{ENV['SINATRA_ENV']}.sqlite"
      )
    end
    
    configure :production do
      db = URI.parse(ENV['DATABASE_URL'] || 'postgres://localhost/mydb')
    
      ActiveRecord::Base.establish_connection(
        :adapter => db.scheme == 'postgres' ? 'postgresql' : db.scheme,
        :host     => db.host,
        :username => db.user,
        :password => db.password,
        :database => db.path[1..-1],
        :encoding => 'utf8'
      )
    end
    
    require_all 'app'
    
  5. The Procfile was something I couldn’t figure out. The SitePoint article I linked above had this line for it and this is what made it all work web: bundle exec rackup config.ru -p $PORT.

  6. For the rest I followed the Ruby docs on Heroku here and the SQLite doc here.
  7. If you get db migration errors you can run rake tasks on Heroku. heroku run rake db:migrate was one that I needed to do. More in depth docs about it here.

Hey, look at that. I remembered way more than I thought. Hopefully, this was helpful to someone somewhere. Probably a student coming behind me who is going to pull their hair out trying to get their app to work on Heroku.

Time spent today: 8:32
Time spent total: 198:13
Lessons completed today: 1
Lessons completed total: 406

Are you Gifted?

Not much to report today. I got some free passes from being a member of American Mensa to see Gifted. So the wife and I went to see that tonight. It’s a good movie and I recommend it.

I finished up the controller and views for one part of my Sinatra project. It’s coming along nicely. Now that I have this done I don’t think the next two controllers and associated views will take as long. It should be pretty close to the same thing just modifying some small amounts of code. I am still deciding between radio buttons and a dropdown for some of my create and update forms. Parents will only be allowed to be associated with one house so deciding how to visually represent that. I think the dropdown will work better only because this app could potentially have a lot of entries in it. I also need to code in that when a House is deleted so are the members of the house. However, I’ll work on that once I actually have associated members.

Time spent today: 1:00
Time spent total: 189:40
Lessons completed today: 0
Lessons completed total: 405

Happy Easter

I decided to take the weekend off and enjoy the Easter holiday with the family. I had been going hard for almost 7 straight weeks. Back at it tomorrow. I also ordered my Code & Quill Origin this weekend. Looking forward to getting my notebooks just in time to take notes on Rails.

Time spent today: 0:00
Time spent total: 188:40
Lessons completed today: 0
Lessons completed total: 405

Make It Look Nice

So about that not being fancy that I talked about last night. I took a good chunk of time today and figured out how to implement Bootstrap in my portfolio project. I figured this was my first web app and should probably look somewhat nice. I have a navbar that changes if you’re logged in or not and then I’m using the form and typography stylings. It’s definitely taking me longer to write my forms out and I’m making sure my app actually will look good so that is taking more time as well. However, I think I’m going to be more proud of this when I’m done. You can follow my progress on my project here. Although, that link might break in the future as I’ll probably rename my repo to something less stalkerish lol.

It took me a long time to get my naming correct for my has_many to has_many relationship. Between the models and the DB it was a mistake in what needed to be plural that ultimately took some time to figure out. I’m happy that I don’t have to keep up with these associations in any complex manner. I don’t know why but I’m exhausted right now. I’m usually still humming along at 11:15pm but not tonight. I’m fighting to stay awake. I made some great progress today on my Sinatra project and I’m happy with where I’m at. I could’ve been closer to being done but I know that I’ll be more proud to show off my project because of how it looks.

Time spent today: 6:20
Time spent total: 188:40
Lessons completed today: 0
Lessons completed total: 405

Crushing Fwitter Tonight was Sweet

It’s late so I’ll be brief. I crushed my project tonight and I’m ready to start my Sinatra portfolio project tomorrow. I think I can have an ugly version (desktop down design, raw forms, no nav bar or footer) done tomorrow at some point and then leave it alone until after my project review with an instructor. We’ll see how that goes. The requirements are:

  1. Build an MVC Sinatra Application.
  2. Use ActiveRecord with Sinatra.
  3. Use Multiple Models.
  4. Use at least one has_many relationship
  5. Must have user accounts. The user that created a given piece of content should be the only person who can modify that content
  6. You should validate user input to ensure that bad data isn’t created

So it might be ambitious to think I can finish that in a day or two but I’m confident I can with what I have planned.

I was able to utilize Active Record Validations tonight. I also included HTML5 required tags in my forms. However, the tests were sending raw params data to the post route so it was bypassing utilizing my forms to test. I guess this is good though because it creates a situation where if someone sends bad data to the server through a method other than the server it’ll reject it. However, I wouldn’t want the server hit every time a bad form is input. Maybe a combo of the two makes sense? That way data is validated in the browser and when being saved to the server. Here’s what an Active Record Validation looks like from Rails Guides:

class Person < ApplicationRecord
  validates :name, presence: true
end

Person.create(name: "John Doe").valid? # => true
Person.create(name: nil).valid? # => false

I also decided to buy the Cast Iron Design Eco Pocket-Sized Notebook pack of 3 to start. I realized that AMEX is offering a bonus if you redeem points towards purchases until the end of the month. While redemption values are almost always lowest when using AMEX points for bill credits with the 20% bump it’s worth using for a few small things. Considering we have 70k of them $12 won’t make a dent in that. I still plan to get a Code & Quill Origin when they’re not sold out anymore. The fact that there are spacing markers that will make written code look good is sweet (not like you can’t do that on graph paper but still).

I think one of the biggest things I’ve been doing that has helped me not get bogged down as I’m moving through the curriculum and projects is to not get too fancy. I’m also not overthinking it. I’m being very straightforward in what I’m putting together and making things that work. Could pretty much everything be better? Yes. However, I’m looking to have a body of work to present. I honestly feel that when it comes job hiring time the strength of the code will outweigh the shiny UI’s. I still plan on going back and polishing everything up and making it look nice (or at least nicer) than the project requirements require.

Time spent today: 3:13
Time spent total: 182:20
Lessons completed today: 1
Lessons completed total: 405

Writing it Down Always Helps

Taking it easy tonight. I have to get some work done for Gift of Adoption Fund, the non-profit I volunteer on the board for here in TN. Shameless plug, Like our Facebook Page please. I finished up the NYC lab in <30 minutes. The second controller and views were much more simple. I didn’t get a chance to refactor my code yet. However, I don’t think helper methods are needed as I didn’t use that code anywhere in my other controller. Maybe though, maybe. I watched the two lecture videos and finished my DB migrations and building out the models on my first Sinatra project as well tonight. I still go back and forth with feeling like I’m getting enough accomplished each day but hitting milestones and goals (even if 3 days late) feels good. My wife is off Friday so hopefully, that’ll allow me some good time to get work done since we have a birthday party Saturday and it’s Easter on Sunday.

On another note, I’m trying to figure out a notebook to buy. I’ve used Moleskine’s in the past. Nothing against them but not what I’m looking for right now. Field Notes seem expensive for what they are and you’re paying for the cool factor more than the notebook. So, I did some research. Deciding between the Cast Iron Design Eco Pocket-Sized Notebook, any of the Code & Quill books although at this price I’d go hardcover, Word. Dot Grid because it’s Field Notes but not, or MUJI Recycled Paper Bing Notebook A5 because they’re dirt cheap. Let me know what you think. I’m leaning towards Code & Quill most likely. I think the larger hardcover books will be beneficial to have segmented by language and framework. I can create personal reference libraries in them and add as time goes on. I can have a master Ruby book, a JS book, a Rails book, is the thought at least. Or maybe I start with smaller books and if a top turns in to two books it gets a C&Q book and I transcribe over what I already have which wouldn’t be much at that point.

Time spent today: 1:50
Time spent total: 179:08
Lessons completed today: 3
Lessons completed total: 404

Helper Methods Tested, How to Not Repeat Yourself

I’m on a killer roll right now blowing through this NYC lab. Built my 3 tables and 1 JOIN table migrations. Built out the associated models. Built out all the views and one controller. Have one controller and its views left now. If I didn’t have kids that were going to wake me up between 6:30am and 8:00am I’d finish it up. I think it’ll take me maybe 30 more mins (mostly because A LOT of it is going to be similar to the controller & views I just built) but sleep is needed. I also need to finish doing my part of the household chores (dishes tonight) before bed so in the interest of rest I’ve stopped.

However, I’m pretty hype and think I’ll still be on schedule to finish the review videos tomorrow night. I also feel more confident about attacking the portfolio project. The only part I haven’t really dug into is the UI. I figure a basic bootstrap will do. Utilize the layout.erb to have a consistent header and footer and I’ll be happy at this point in time (when that time comes).

I’m contemplating creating helper methods for my controllers. Currently, the one controller I finished tonight (I’ll do the other and all its views tomorrow) is:

class FiguresController < ApplicationController

  get '/figures' do
    @figures = Figure.all
    erb :'figures/index'
  end

  get '/figures/new' do
    @figures = Figure.all
    @landmarks = Landmark.all
    @titles = Title.all
    erb :'figures/new'
  end

  get '/figures/:id' do
    @figure = Figure.find(params[:id])
    erb :'figures/show'
  end

  post '/figures/:id' do
    @figure = Figure.find(params[:id])
    @figure.update(params[:figure])

    if !params[:title][:name].empty?
      if !!params[:figure][:title_ids]
        params[:figure][:title_ids] << Title.create(params[:title]).id
      else
        params[:figure][:title_ids] = []
        params[:figure][:title_ids] << Title.create(params[:title]).id
      end
    end
    @figure.title_ids = params[:figure][:title_ids]

    if !params[:landmark][:name].empty?
      if !!params[:figure][:landmark_ids]
        params[:figure][:landmark_ids] << Landmark.create(params[:landmark]).id
      else
        params[:figure][:landmark_ids] = []
        params[:figure][:landmark_ids] << Landmark.create(params[:landmark]).id
      end
    end
    @figure.landmark_ids = params[:figure][:landmark_ids]

    @figure.save

    redirect to "/figures/#{@figure.id}"
  end

  get '/figures/:id/edit' do
    @figure = Figure.find(params[:id])
    @landmarks = Landmark.all
    @titles = Title.all
    erb :'figures/edit'
  end

  post '/figures' do
    @figure = Figure.create(params[:figure])

    if !params[:title][:name].empty?
      if !!params[:figure][:title_ids]
        params[:figure][:title_ids] << Title.create(params[:title]).id
      else
        params[:figure][:title_ids] = []
        params[:figure][:title_ids] << Title.create(params[:title]).id
      end
    end
    @figure.title_ids = params[:figure][:title_ids]

    if !params[:landmark][:name].empty?
      if !!params[:figure][:landmark_ids]
        params[:figure][:landmark_ids] << Landmark.create(params[:landmark]).id
      else
        params[:figure][:landmark_ids] = []
        params[:figure][:landmark_ids] << Landmark.create(params[:landmark]).id
      end
    end
    @figure.landmark_ids = params[:figure][:landmark_ids]

    @figure.save

    redirect to "/figures/#{@figure.id}"
  end
end

The main parts that violate DRY (don’t repeat yourself) should be readily evident in:

if !params[:title][:name].empty?
  if !!params[:figure][:title_ids]
    params[:figure][:title_ids] << Title.create(params[:title]).id
  else
    params[:figure][:title_ids] = []
    params[:figure][:title_ids] << Title.create(params[:title]).id
  end
end
@figure.title_ids = params[:figure][:title_ids]

if !params[:landmark][:name].empty?
  if !!params[:figure][:landmark_ids]
    params[:figure][:landmark_ids] << Landmark.create(params[:landmark]).id
  else
    params[:figure][:landmark_ids] = []
    params[:figure][:landmark_ids] << Landmark.create(params[:landmark]).id
  end
end
@figure.landmark_ids = params[:figure][:landmark_ids]

Not only are these lines with a nested if statement not elegant but they are carbon copies of each other. In addition, I foresee using almost the same exact methods in my other controller. I’ll probably have one of these if blocks utilizing figure_ids but other than that it’ll be pretty close. We’ll see and if that’s true I’ll definitely create 3 helper methods and just use those if I can. It’ll be good practice in building helper methods for the controller because I haven’t done that before. I’ve built a module for the models in my last lab.

A note I took that didn’t make sense at the time was:

Define helper methods in the Application Controller

After tonight I see exactly why. This is because the individual controllers (at least in my case) are inheriting from the app controller. I was thinking initially I would have to create a Helper class of some sort and then utilize them that way but I have this basically empty file that the controllers are already using so it makes sense to put helper methods right in there.

Time spent today: 2:09
Time spent total: 177:17
Lessons completed today: 0
Lessons completed total: 401