Retrospective record of making flea market apps

Overview

It took a week and two days to create a simplified version of the flea market app using Ruby and JavaScript. It is a personal record of the points I stumbled upon and how I got over it.

Overview of the app created this time

Flea market apps

Use Ruby on Rails 6.0.0

Database design

** Where I was interested **

Completed DB
## Users table
Column Type Options
nickname string null: false
email string null: false, unique: true
encrypted_password string null: false
first_name string null: false
last_name string null: false
first_name_k string null: false
last_name_k string null: false
birth date null: false

Association has_many :items has_many :order

Item table

Column Type Options
name string null: false
text text null: false
category_id integer null: false
condition_id integer null: false
delivery_fee_id integer null: false
prefecture_id integer null: false
delivery_day_id integer null: false
price integer null: false
user references null: false, foreign_key: true

Association belongs_to :user belongs_to :category_id belongs_to :condition_id belongs_to :delivery_fee_id belongs_to :prefecture_id belongs_to :delivery_day_id has_one :order

Order table

Column Type Options
user references null: false, foreign_key: true
item references null: false, foreign_key: true

Association belongs_to :user belongs_to :item has_one :address

Address table

Column Type Options
postal_cord string null: false
prefecture_id integer null: false
city string null: false
house_number string null: false
building string
phone_number string null: false
buy_record references null: false, foreign_key: true

Association belongs_to :order belongs_to :prefecture_id

ED diagram スクリーンショット 2020-12-16 15.05.20.png

User management function

** Rough flow **

** Where I stumbled **

** Solution **

`password` validation settings

Until I created this flea market app, I was upset because I had hardly tampered with the validation of email and password of devise. By default, it seems that password can be registered with just numbers. I had to validate email myself because I would remove the entire validation that comes with devise.

The following are (1) remove the default validation of devise (2) regular expression that applies alphanumeric character required validation to password (3) convenient for applying multiple validations with_options (4) necessary to match the input twice. I'm writing about validation.

user.rb


class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
                                       #↑ Delete
# 'password'Regular expression to validate
# '.freeze'Is'PASSEOWD_REGEX'Method to prevent rewriting
  PASSWORD_REGEX = /\A(?=.*?[a-z])(?=.*?[\d])[a-z\d]+\z/i.freeze

# 'with_options'Allows you to add multiple options to validation at once
# 'confirmation'→':password'When':password_Does the value received in confirmation match?
  with_options presence: true, format: { with: PASSWORD_REGEX, message:'Please include both letters and numbers in' }, length: { minimum: 6 }, confirmation: true do
    validates :password
  end

Reference site [Rails] Customize devise validation Active Record Validation (https://railsguides.jp/active_record_validations.html#confirmation)

`email` validation settings

This is a validation to prevent the email from being registered twice. uniqueness is applicable. case_sensitive: false is case insensitive.

user.rb


# 'uniqueness'→'email'Validate the uniqueness of
#With regular expression'@'Instructed to include
with_options presence: true, format: { with: /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i, message: '@Please enter including' }, uniqueness: { case_sensitive: false } do
    validates :email
  end

Reference site [Rails] Email Address Validation [Rails] Verification of uniqueness of email address [Rails Tutorial Chapter 6 Summary] instance method Object#freeze

Generate dummy data for users using Kanji and Frigana, and dummy data for date of birth

Until now, I had only used Faker to create dummy data, so I was confused as to" What is the name of the kanji? And also Frigana? ", But when I searched, I found the perfect library. ..

spec/factories/users.rb


FactoryBot.define do
  factory :user do
    #Omission
    first_name {Gimei.first.kanji}
    last_name {Gimei.last.kanji}
    first_name_k {Gimei.first.katakana}
    last_name_k {Gimei.last.katakana}
    birth {Faker::Date.between(from: '1990-01-01', to:'2020-12-08')}
  end
end

Thank you very much for making Gimei ... Reference site [Rails] Generate Japanese dummy data with gem ‘gimei’ [Japanese Faker] About the gem "gimei"

Additional modifications

This is a correction that was returned after requesting a review.

spec/factories/users.rb


factory :user do
  #Omission
  password = Faker::Internet.password(min_length: 6)

If left unchecked,'Faker' may generate a password with only numbers, which can lead to errors.

spec/factories/users.rb


password = '1a' + Faker::Internet.password(min_length: 6)

I fixed it to.

Product listing function

** Rough flow **

** Where I stumbled **

** Solution **

Calculate the amount on the screen

I want to make this 1e92f5550e5e4dd2f60f79b3a8b681a0.gif

javascript/card.js


function price() {
  const priceInput = document.getElementById("item-price");

  priceInput.addEventListener("input", () => {
    const inputValue = priceInput.value;
    const addTaxDom = document.getElementById("add-tax-price");
    const profit = document.getElementById("profit");

    addTaxDom.innerHTML = Math.floor(inputValue * 0.1);
    profit.innerHTML = Math.floor(inputValue - inputValue * 0.1);
  })
}

window.addEventListener('load', price)

First, getElementById ("item-price") gets the element to enter the amount, and priceInput.value gets the value entered. Using this inputValue, the value calculated in () of Math.floor will be rounded off to the nearest whole number, and the commission and profit amount of 10% of the entered amount will be displayed on the screen. I can put it out. Reference site Active engineers explain how to use the Math.floor method of JavaScript [for beginners]

Set a range of values ​​for validation

Since the amount that can be set by the user is ¥ 300 to ¥ 9,999,999, it is necessary to set the validation that only this range can be entered.

item.rb


  with_options presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 300, less_than_or_equal_to: 9999999 } do
    validates :price
  end

You have now set a range of values ​​for validation. Reference site Use numericity to verify that only numbers are used for attributes

Product list display / edit / delete function

I proceeded smoothly here. Be careful because DRY's law tends to be missed.

Product purchase function

Here, we worked on two major new things. ① Introduction of open API ② Form object pattern is.

Implemented product purchase function

When the application implements the purchase function, it is not recommended to receive the card information directly from the user and process the payment because of the large amount of paperwork and the difficulty of ensuring certain security standards. Therefore, we will implement it via a credit card payment agency service. This time I used PAY.JP.

As a processing flow ① The user inputs the card information on the card input screen ② ① is tokenized and the token is sent to the server side To do.

In addition, in this application, one form is used for (1) tokens, (2) purchase information (id record of the purchased user and id record of the purchased product), and (3) delivery destination information, three different tables (or not). Must be saved at once. Until now, I have only created an application that supports only one table for one form. The Form object pattern is used here. As a flow (1) Create a new file directly under the model directory, define a class, and set ActiveModel :: Model to inclede. ② Use attr_accessor to use all the attributes used in this form. ③ Describe the validation process ④ Describe the process of saving the received data It's a feeling.

model/user_order.rb


class UserOrder
  include ActiveModel::Model
  attr_accessor :token, :postal_code, :prefecture_id, :city, :house_number, :building, :phone_number, :item_id, :user_id

  with_options presence: true do

    validates :token
    
    validates :postal_code, format: { with: /\A\d{3}[-]\d{4}\z/, message: "is invalid. Include hyphen(-)"}
    validates :city, format: { with: /\A[Ah-Hmm-One-龥]/, message: "is invalid. Input full-width characters."}
    validates :house_number
    validates :phone_number, format: { with: /\A\d{10,11}\z/, message: "is invalid."}
    validates :user_id
    validates :item_id
  end
  
  validates :prefecture_id, numericality: { other_than: 1, message: "can't be blank" }

  def save
    order = Order.create(user_id: user_id, item_id: item_id)
    Address.create(postal_code: postal_code, prefecture_id: prefecture_id, city: city, house_number: house_number, building: building, phone_number: phone_number, order_id: order.id)
  end
end

Now you can handle data from multiple tables at once in one form. Also, since attr_accessor is used when you want to handle attributes other than the column name of the table that originally corresponds to the (?) Model, you can also handle the value of: token that has no column in the table. This is because it automatically does a getter that allows you to get the value and a setter that allows you to update the value, but I'm going to go a little deeper next time.

Another thing I stumbled upon was the place to put the letters Sold Out after purchasing.

How to change the display depending on whether you purchased it

Here, describe the conditional branch "Does the data of order exist? "In the view file in the data of each product.

views/order/index.html


<% if item.order.present? %>
  <div class='sold-out'>
    <span>Sold Out!!</span>
  </div>
<% end %>

Reference site Let's master nil? Blank? Empty? Present? In Rails

The rest is Basic authentication & deployment and the end. To be honest, I was confused because there were many things nice to meet you, but I managed to achieve the basic implementation. I will make an original from now on, so I will not be able to see the goal further, but I will do my best. From now on, I would like to write diligently to organize information.

Recommended Posts

Retrospective record of making flea market apps
Implementation of digit grouping in flea market apps
Don't forget to summarize the features and points of the flea market apps