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)