DEV Community

Liz Laffitte
Liz Laffitte

Posted on • Edited on

Building a Social Media Marketing App (Part II)

In Part I, I went over why I want to build a social media marketing app, the languages and frameworks I plan to use, some user stories and how I got started.

At this point in the application building process, I made myself stop and do more thorough database planning. I decided on my models, their attributes and their relationships to each other. In an effort to keep this short and sweet, I’ll just highlight a few snippets of my model planning:

Users

  • role string
  • email string
  • password_digest string
  • username string

  • has_many :created_posts, class_name: “Post”, foreign_key: :creator_id

  • has_many :assigned_posts, class_name: “Post”, foreign_key: :assignee_id

  • has_many :pages

Post

  • platform string
  • content text
  • link string
  • page_id , foreign_key

  • belongs_to :creator, class_name: “User”, foreign_key: :creator_id

  • belongs_to :assignee, class_name: “User”, foreign_key: :assignee_id

  • belongs_to :page

I started with my User model. First I rolled my migration back, to add some attributes missing from my initial migration. This is what my final (for now) Create Users migration looks like:

class CreateUsers < ActiveRecord::Migration[6.0]
  def change
    create_table :users do |t|
      t.string :username
      t.string :password_digest
      t.string :email
      t.string :role
      t.timestamps
    end
  end
end
Enter fullscreen mode Exit fullscreen mode

With my new model set up, I started writing my initial tests, based on how I want to define a valid User.

require 'rails_helper'

RSpec.describe User, type: :model do
  subject {User.new(username:'Robert')}

  before {subject.save}

  it 'should have a username' do
    subject.username = nil
    expect(subject).to_not be_valid
  end

  it 'should have a unique username' do
    user = User.create(username:'Sam')
    subject.username = 'Sam'
    expect(subject).to_not be_valid
  end

  it 'should have an email address' do
    subject.email = nil
    expect(subject).to_not be_valid
  end
end
Enter fullscreen mode Exit fullscreen mode

The the code snippet above, the tests are describing what a valid User should have. A User should have a username, so if a User instance doesn't have a username, it isn't valid.

To make sure my tests were all passing, I added validations to be user model.

class User < ApplicationRecord
    validates :username, presence: true, uniqueness: true
    validates :email, presence: true
    has_secure_password
end
Enter fullscreen mode Exit fullscreen mode

The last line of code in my User model is in reference to the bcrypt gem.

In an effort to not get ahead of myself, and build vertically, I decided that now was the perfect time to built out my first User controller action.

/app/controllers/users_controller.rb

class UsersController < ApplicationController
    wrap_parameters :user, include: [:username, :password, :email]

    def create
        @user = User.new(user_params)
        if @user.save
            session[:user_id] = @user.id
            render json: {user: @user.username ,status: :created}
        else 
            render json: {error: @user.errors.full_messages.to_sentence, status: :unprocessable_entity}
        end

    end

    private

    def user_params
        params.require(:user).permit(:username, :email, :password)
    end
end
Enter fullscreen mode Exit fullscreen mode

In the code snippet above, I define a private method that specifies what params we're permitting when the signup form is completed. To make sure this works, I'm also wrapping my parameters at the start of the controller. The user#create action saves valid users and renders an error when a user is invalid.

Then I hopped over to config/routes.rb to match my signup route to my new controller action.

Rails.application.routes.draw do
  post '/signup', to: "users#create"
end
Enter fullscreen mode Exit fullscreen mode

After completing this step, my first inclination was to build the signup form and test the create action manually. But we're learning and growing, so we wrote a request spec instead!
spec/requests/users_request_spec.rb

require 'rails_helper'

RSpec.describe "Users", type: :request do
    describe "POST users#create" do
    it "creates a new user with valid attributes" do
      user_params = {
        user: {
            username: 'TaterTot',
            email: 'tatertot@aol.com',
            password: 'potatoes'
        }
      }
      post '/signup', :params => user_params.to_json, :headers => { "Content-Type": "application/json" }
        json = JSON.parse(response.body)
        expect(response).to have_http_status(201)
    end

  it "renders an error with invalid attributes" do
    user_params = {
      user: {
          username: 'TaterTot',
          email: 'tatertot@aol.com'
      }
    }
    post '/signup', :params => user_params.to_json, :headers => { "Content-Type": "application/json" }
      json = JSON.parse(response.body)
      expect(json["error"]).to include("Password can't be blank")
  end
end

end

Enter fullscreen mode Exit fullscreen mode

Ta-da! We are up to 6 passing examples (but who's counting)! In this post, I described the creation of my first model, its first corresponding controller action and a few request specs. In Part III, I'll continue the vertical build, connecting the React frontend, and building out the Signup component.

Top comments (0)