Let's build for Ruby and Rails developers - Part 4
Tags: rails, ruby, tutorial, video
Published: 2020-08-07 16:01:59

---
title: Let's build for Ruby and Rails developers - Part 4
published: true
date: 2020-08-03 14:43:00 UTC
tags: rails, ruby, tutorial, video
canonical_url: https://web-crunch.com/posts/lets-build-for-ruby-and-rails-developers-part-4
---

{% youtube XoDG-7jX4mM %}

## Creating the core data models

Welcome to part 4 of my Let's build for Ruby and Rails developers series. This part will focus on generating our core model layer inside the Ruby on Rails application.

Find the code for this session [here](https://github.com/justalever/railsdevs_public/tree/part_4) or by clicking the button in the sidebar to the right.

## Data modeling

The core models we'll leverage in this app, to begin with, will be the `Job` and `User` model. In a previous part, I mentioned taking a simpler route with the `User` model that prefers `boolean` attributes as to a fully separated persona of user models.

Our `User` model ends up with a few sets of boolean columns including:

- `developer`
- `admin`
- `employer`

We got there by generating a new migration:

```bash
rails g migration add_personas_to_users developer:boolean employer:boolean

```

Inside the migration file I added a default value to `false` for each column:

```ruby
# db/migrate/XXXXXXXXXXXXX_add_personas_to_users.rb
class AddPersonasToUsers < ActiveRecord::Migration[6.0]
  def change
    add_column :users, :developer, :boolean, default: false
    add_column :users, :employer, :boolean, default: false
  end
end

```

A given `User` can be any combination of these. Coming up I'll create some helpful methods that make checking against these constraints easier to handle. We'll leverage these throughout the app.

### Updating Devise

Because we are updating our `User` model we need to permit additional parameters on via the Devise gem. This takes place in our `application_controller.rb` file and looks like this:

```ruby
# app/controllers/application_controller.rb
...
def configure_permitted_parameters
  keys = [:name, :developer, :employer]
  devise_parameter_sanitizer.permit(:sign_up, keys: keys)
  devise_parameter_sanitizer.permit(:account_update, keys: keys)
end

```

With this intact, we can now pass these values from the front-end during user sign up and update actions.

Our views need some updates to include these new fields as well

```erb
<!-- app/views/devise/registration/edit.html.erb -->
<h3 class="mb-4 text-lg font-bold">Roles</h3>

<div class="input-group">
  <%= f.check_box :developer %>
  <%= f.label :developer, "Use railsdevs.com as a developer?" %>
</div>

<div class="input-group">
  <%= f.check_box :employer %>
  <%= f.label :employer, "Use railsdevs.com as an employer?" %>
</div>


<!-- app/views/devise/registration/new.html.erb -->
<h3 class="mb-4 text-lg font-bold">Roles</h3>

<div class="input-group">
  <%= f.check_box :developer %>
  <%= f.label :developer, "Use railsdevs.com as a developer?" %>
</div>

<div class="input-group">
  <%= f.check_box :employer %>
  <%= f.label :employer, "Use railsdevs.com as an employer?" %>
</div>

```

### The `Job` model

Our other core model is of course the `Job` model. The main focus of this app is a job board for ruby and rails developers. We'll be paying the most attention to this model by design.

To save a lot of time I generated a scaffold for the Job resource.

Initially, we'll add some columns I know we need but later on, this might need to be tweaked. We can do that with additional migrations or go back in time using `rails db:rollback` to tweak the initial migration. We'll cross that bridge once we get to it.

```bash
rails g scaffold Job company_name company_website compensation_range link_to_apply remote:boolean role_type title years_of_experience user:references

```

There's a lot going on in the code above but at its core, we'll be generating a full RESTful construct for the `Job` model. This effectively creates a new database table called `jobs`, and all the files relative to the MVC concept in a Ruby on Rails application. We'll get some extra files we don't need but that's okay for now. We can always do some housekeeping later.

Note the names I passed after `Job` in the string above. Each of these will generate a new column on the `jobs` database table. For each name, you can pass additional options prefaced by a `:` sign. Note the `remote:boolean` option. This tells ActiveRecord (the DSL language and library that talks to the database for us) that this column should be a `boolean` type.

If you don't pass the option at all it's assumed a type of `String` in the database.

Running this generator should create a full resource for `Job` as well as set a reference to our `User` model thanks to the `user:references` option. This option is a huge time saver that automatically generates a `user_id` column on the `jobs` database table. From there, we can assign a given user a job once they create a new one which effectively allows them to "own" that specific job. This will be useful coming up when we want to give users the ability to create, edit, update, and delete a job on their own.

Once the generation is complete you may notice some updates to the `app/models/job.rb` file after creation. There should be a new `belongs_to :user` association already in place.

We still need to add an additional association to the `app/models/user.rb` file but that's a quick and easy task:

```ruby
# app/models/user.rb
class User < ApplicationRecord
  include SimpleDiscussion::ForumUser
  has_person_name
  has_many :jobs, dependent: :destroy # add this line
  ...
end

```

Because a `Job` belongs to a `User`, we want a user to be able to "own" and manage multiple jobs. The line above allows just that.

The `dependent: :destroy` option means that if a `User` account is deleted for whatever reason, all the associated jobs will be deleted as well. This is a good practice to keep only the necessary data in your database at all times. You don't always need this option(especially if you want to retain that data) but I think it's a good practice for the most part.

### A few view updates

Aside from those major updates, I took a brief moment to update our main views

```erb
<!-- app/views/shared/_head.html.erb -->
    <% if content_for?(:title) %>
      <%= yield :title %> |
    <% end %>
    railsdevs.com
  </title>

  <%= csrf_meta_tags %>
  <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  <%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
  <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  <%= javascript_include_tag 'https://js.stripe.com/v3/', 'data-turbolinks-track': 'reload' %>
</head>

```

Our `_head.html.erb` partial now loads the Stripe.js library we'll need later on and we updated the site title to `railsdevs.com`.

Inside our `app/views/shared/_header.html.erb` file I added a quick access link to our new job resource. We'll change this later on but for now, this makes it easier to navigate to.

```
<!-- around line 11 -->
<div class="items-center block w-full text-center lg:flex-1 lg:flex lg:text-left">
      <div class="lg:flex-grow">
        <%= link_to "Basic Link", "#", class: "block mt-4 lg:inline-block lg:mt-0 lg:mr-4 mb-2 lg:mb-0 link" %>
        <%= link_to "Jobs", jobs_path, class: "block mt-4 lg:inline-block lg:mt-0 lg:mr-4 mb-2 lg:mb-0 link" %>
      </div>
      <div class="items-center block w-full mt-2 text-center lg:flex lg:flex-row lg:flex-1 lg:mt-0 lg:text-left lg:justify-end">
        <% if user_signed_in? %>

```

### Install action text and active storage

Finally, we installed both action text and active storage in one command:

```bash
rails action_text:install

```

This should fetch the appropriate JavaScript and Ruby dependencies we'll leverage later on.

#### The series so far

- [Part 1](https://dev.to/justalever/let-s-build-for-ruby-and-rails-developers-2g1)
- [Part 2](https://dev.to/justalever/let-s-build-for-ruby-and-rails-developers-part-2-3310)
- [Part 3](https://web-crunch.com/admin/posts/lets-build-for-ruby-and-rails-developers-part-3/)
- Part 4 (You are here)