美文网首页
山竹记账-环境搭建

山竹记账-环境搭建

作者: sweetBoy_9126 | 来源:发表于2022-04-05 18:07 被阅读0次

    Docker

    问:如果开发环境与生产环境系统不一致会不会有 bug ?
    答:可能会有 bug(如缺少依赖库、API 不兼容等)
    解决方式:尽量保证环境一致,推荐使用 Docker

    优点

    在 Windows 里运行 Linux 容器
    在 macOS 里运行 Linux 容器
    在 Linux 里运行 Linux 容器
    在所有地方用同一套环境!

    缺点

    你需要了解容器的概念
    你需要做端口映射
    你需要做数据卷映射
    你需要会 Linux 命令
    即,有学习门槛
    另外,会占用内存和硬盘

    使用 Docker + Vscode

    • 使用模板代码
      下载我准备好的代码[https://github.com/FrankFang/oh-my-env-1],下载后删除 .git 即可使用
      使用 VSCode 打开该目录,按下 Ctrl + Shift + P
      输入 reopen in container,回车,如果报错,在命令行输入如下命令
    docker network create network1
    

    等待片刻,你就进入了我的开发环境

    • 测试命令是否可用
      新建终端,输入视频中的命令
      确保 ruby、bundle、irb、node 和 npm 等命令可用

    • 工作空间
      oh-my-env 会自动映射为 /workspaces/oh-my-env
      该目录里的文件是内外共享的,性能一般
      我提前准备好了 ~/repos 目录,该目录是该容器专属的,性能较好
      我默认会在 ~/repos 中工作
      需要共享时才会用到 /workspaces/oh-my-env/temp 目录

    • 持久化
      在 Ctrl + Shift + P 弹出框内输入 rebuild container
      相当于重装系统
      只有 mounts 中的目录和 oh-my-env 目录被保留

    • 现有功能
      archlinux、zsh、fzf、rvm + ruby、nvm + node、go、
      docker in docker、chezmoi、各种国内加速……

    • 如何自定义
      打开 .devcontainer/Dockerfile
      用 RUN 指令来添加你想要添加的依赖
      如 RUN yes | pacman -S fish
      然后 rebuild container 即可
      更多功能请看 FrankFang/oh-my-docker

    新建项目

    • 创建目录
      mkdir ~/repos/hello
      code ~/repos/hello
    • 切换窗口
      关闭 oh-my-env 窗口
      使用 hello 窗口
    • 原则
      每次只打开一个目录
      不要一次打开很多目录,会卡

    2.搭建后端项目

    从无到有创建 Rails API

    2.1. 初始化目录

    rvm use 3 // 使用 ruby
    // 使用国内镜像
    gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/
    bundle config mirror.https://rubygems.org https://gems.ruby-china.com
    
    // 安装 rails
    gem install rails -v 7.0.2.3
    // 安装 postgresql 驱动
    pacman -S postgresql-libs
    cd ~/repos
    
    // rails new创建新项目 --api只使用api模式  --database=postgresql 指定使用postgresql数据库;--skip-test 跳过测试;mangosteen-1 目录名
    rails new --api --database=postgresql --skip-test mangosteen-1
    // 打开项目
    code mangosteen-1
    // 开启 server
    bundle exe rails server
    // 需要关闭 server 请按 Ctrl + C
    

    2.2. 启动数据库

    上面我们开启了 server 但是打开报错

    原因是没有数据库;

    在linux 外的命令行运行如下命令

    // docker run 启动新的容器 
    // -d 不要断开
    // \ 这一行没有结束
    // --name 容器的名字
    // -e 环境变量 POSTGRES_USER 用户名
    // -v 新增数据卷
    // --network 指定网络
    //  postgres:14 镜像名称 postgres 版本 14
    docker run -d \
        --name db-for-mangosteen \
        -e POSTGRES_USER=mangosteen \
        -e POSTGRES_PASSWORD=123456 \
        -e POSTGRES_DB=mangosteen_dev \
        -e PGDATA=/var/lib/postgresql/data/pgdata \
        -v mangosteen-data:/var/lib/postgresql/data \
        --network=network1 \
        postgres:14
    

    2.3. 连接数据库

    修改项目里的 config/database.yml
    development:
    <<: *default
    database: mangosteen_dev
    username: mangosteen
    password: 123456
    host: db-for-mangosteen

    再次运行 bundle exe rails server

    2.4 设计数据库

    两种思路

    自上而下:先想大概,再添细节
    自下而上:用到什么加什么,会出现打脸的情况
    两种思路可以混合,我们先采用自下而上

    工具

    g 创建 model 模型 user 模型名称 email 和 name 是需要的字段,我们的用户信息暂时只需要 email 和 name

    • 1.建模工具
    bin/rails g model user email:string name:string
    

    运行完成后


    image.png

    会创建两个文件

    • create_users.rb
    class CreateUsers < ActiveRecord::Migration[7.0]
      # 对数据库的修改
      def change
        # 创建一个表,表的名字是 users,do就相当于一个函数,也就是对这个表的字段变更
        create_table :users do |t|
          # t.string 添加一个string名字是email
          t.string :email
          t.string :name
          #t.timestamps 会生成两个字段 updated_at(更新时间) 和 created_at(创建时间)
          t.timestamps
        end
      end
    end
    
    

    数据库操作工具:ActiveRecord::Migration

    1. 同步到数据库:bin/rails db:migrate
      反悔命令:bin/rails db:rollback step=1

    2.5. 创建路由

    • routers.rb
    Rails.application.routes.draw do
      # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
      # 当你发送一个 post 请求到 /users 会调用 users的create方法
      post  '/users', to: 'users#create'
      get  '/users/:id', to: 'users#show'
    end
    

    创建create 和 show 方法

    bin/rails g controller users create show
    

    会创建一个 users_controller.rb

    class UsersController < ApplicationController
      def create
        p '你访问了 create'
      end
    
      def show
        p '你访问了 show'
      end
    end
    

    使用命令行访问 /users

    curl -X POST http://127.0.0.1:3000/users
    

    控制台会打印出 '你访问了 create'
    修改上面的代码创建一个数据

    class UsersController < ApplicationController
      def create
        user = User.new name: 'lifa'
         // 如果保存成功就渲染 user,否则就渲染user的错误
        if user.save
          render json: user
        else 
          render json: user.errors  
        end  
      end
    
      def show
        p '你访问了 show'
      end
    end
    

    添加必填校验,校验 email 必填

    • user.rb
    class User < ApplicationRecord
      validates :email, presence: true
    end
    

    再次运行

    curl -X POST http://127.0.0.1:3000/users
    // {"email":["can't be blank"]}#
    

    对 show 进行改造

    def show
      # 得到id 参数
       user = User.find_by_id params[:id]
        if user
          render json: user
        else
          head 404
        end  
    

    问题

    rebuild 之后,项目就跑不起来了,是为什么?
    答:因为依赖没有被持久化

    哪些依赖没有持久化?
    ruby 的 gems 没有持久化
    archlinux 的 postgresql-libs 没有持久化

    如何解决?

    1. 在容器中运行 code /workspaces/oh-my-env-???/.devcontainer/Dockerfile
      文末添加 RUN yes | pacman -S postgresql-libs

    2. 在devcontainer.json 里的mount 里添加

     "source=gems,target=/usr/local/rvm/gems,type=volume", 
    
    1. 重新 rebuild
      然后运行 bundle install
      安装成功后再次运行
    bundle exe rails server
    

    搭建后端项目

    REST

    一种网络软件架构风格
    不是标准、不是协议、不是接口,只是一种风格
    Roy 于 2000 年在自己博士论文中提到此术语
    Roy 曾参与撰写 HTTP 规格文档
    怎么做?

    1. 以资源为中心
    2. 充分利用 HTTP 现有功能,如动词、状态码、头部字段
    3. GitHub API[https://docs.github.com/en/rest/repos] 就比较符合 REST,值得学习

    REST 风格举例1

    请求1:创建 item
    POST /api/v1/items
    Content-Type: application/json
    消息体 {"amount":99, "kind": "income"}
    响应 {"resource": {...}} 或 {"errors": {...}}
    请求2:创建 item
    POST /api/v1/items
    Content-Type: application/x-www-form-urlencoded
    消息体 amount=99&kind=income

    REST 风格举例2

    请求:更新 item
    PATCH /api/v1/items/1
    Content-Type: application/json
    消息体 {"amount":"11", "kind": "expense"}
    反风格:
    POST /api/v1/modify_item?id=1
    对方观点:全用 POST 多省事儿
    我方观点:有 DELETE 不用非要自己想,多费事儿啊

    REST 风格举例3

    请求:删除 item
    DELETE /api/v1/items/1

    反风格:
    POST /api/v1/remove_item?id=1
    反方观点:POST 省事儿
    我方观点:自己想路径,费事儿

    REST 风格举例4

    请求:获取一个或多个 item
    GET /api/v1/items/1
    GET /api/v1/items?page=1&per_page=10
    GET /api/v1/users/2/items
    GET /api/v1/items?user_id=2
    GET /api/v1/items?tags_id[]=1&tags_id[]=2
    GET /api/v1/items?tags_id=1,2
    GET /api/v1/items?sort_by[]=id+asc&sort_by[]=name+desc
    GET /api/v1/items?keyword=hi
    GET /api/v1/items/search/hi

    REST 风格总结

    1. 尽量以资源为中心
      url 里的 items 就是资源
    2. 尽量使用 HTTP 现有功能
      其实响应头里也可以包含内容,但目前的例子都没有用到
    3. 可以适当违反规则
      比如 /api/v1/items/search/hi

    白话版总结

    看见路径就知道请求什么东西
    看见动词就知道是什么操作
    看见状态码就知道结果是什么
    200 - 成功 201 - 创建成功
    404 - 未找到 403 - 没有权限 401 - 未登录
    422 - 无法处理,参数有问题 402 - 需付费
    412 - 不满足前提条件 429 - 请求太频繁
    400 - 其他所有错误,详细原因可以放在 body 里

    设计 API

    发送验证码

    资源:validation_codes
    动作:create(POST)
    状态码:200 | 201 | 422 | 429

    • routes.rb
    Rails.application.routes.draw do
      # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
    
      namespace :api do
        namespace :vi do
          # /api/v1
          # 如果后缀有s就 resources
          resources :validation_codes
        end
      end
    end
    

    运行 bin/rails routers
    会生成

    GET    /api/vi/validation_codes(.:format)  api/vi/validation_codes#index
    POST   /api/vi/validation_codes(.:format)  api/vi/validation_codes#create
    GET    /api/vi/validation_codes/:id(.:format)  api/vi/validation_codes#show
    PATCH  /api/vi/validation_codes/:id(.:format)  api/vi/validation_codes#update
    PUT    /api/vi/validation_codes/:id(.:format) api/vi/validation_codes#update
    DELETE /api/vi/validation_codes/:id(.:format) api/vi/validation_codes#destroy
    

    我们只想要 create 方法,所以我们可以使用 only

    resources :validation_codes, only: [:create]
    

    登入登出

    资源:session(没有s)
    动作:create | destroy(DELETE)
    状态码:200 | 422

    resource :session, only: [:create, :destroy]
    

    当前用户

    资源:me
    动作:show(GET)

    resource :me, only: [:show]
    

    记账数据

    资源:items
    动作:create | update | show | index | destroy
    update 对应 PATCH,表示部分更新
    show 对应 GET /items/:id,用来展示一条记账
    index 对应 GET /items?since=2022-01-01&before=2023-01-01
    destroy 对应 DELETE,表示删除,一般为软删除

    resources :items
    

    标签

    资源:tags
    动作:create | update | show | index | destroy

    resources :tags
    

    打标签

    资源:taggings(动词的名词形式)
    动作:create | index | destroy

    创建数据表

    // 创建 ValidationCode 数据表 里面有 email字段是字符串类型,kind表示哪一类的验证码(登录/删除),used_at 表示什么时候用验证码
    bin/rails g model ValidationCode email:string kind:string used_at:datetime
    // 把创建的数据表同步到数据库
    bin/rails db:migrate
    

    创建方法

    bin/rails g controller validation_codes create
    

    然后修改我们生成的controller 因为我们需要加/api/v1的前缀,所以首先需要把文件移动到controllers/api/v1 下面,然后在我们的类名上添加 Api::V1::

    class Api::V1::ValidationCodesController < ApplicationController
      def create
      end
    end
    

    也可以直接使用命令行

    bin/rails g controller Api::V1::Validation_codes create
    

    创建 items 支持分页

    1. 创建 item 数据表
    // amount 金额 notes 文章 (text: 长内容,string: 短字符串) tags_id 标签id
    bin/rails g model item user_id:integer amount:integer notes:text tags_id:integer happen_at:datetime
    
    1. 修改生成的 数据表
    class CreateItems < ActiveRecord::Migration[7.0]
      def change
        create_table :items do |t|
          t.bigint :user_id
          t.integer :amount
          t.text :note
          t.bigint :tags_id, array: true
          t.datetime :happen_at
    
          t.timestamps
        end
      end
    end
    
    1. 创建 controller
    bin/rails g controller Api::v1::Items
    
    1. 修改 controller
    class Api::V1::ItemsController < ApplicationController
      def index
        Item.page(1)
      end
      def create
        item = Item.new amount: 1
        if item.save
          render json: {resource: item}
        else 
          render json: {errors: item.errors}
        end
      end
    end
    

    这个时候我们不能通过 .page获取页面,因为没有这个api,我们可以使用kaminari 或 pagy 库
    1). 使用 kaminari
    在 Gemfile 里添加

    gem 'kaminari'
    

    然后运行 bundle 下载后再运行 bin/rails s 重启项目
    注意默认每页里有25条,如果想修改每页的条数,需要使用命令

    bin/rails g kaminari:config
    

    把对应的 kaminari_config.rb 文件注释解开,修改成自己需要的

    Kaminari.configure do |config|
       config.default_per_page = 10
    

    再次重新运行bin/rails s
    修改代码通过参数获取分页

    • items_controller
    def index
        items = Item.page params[:page]
        render json: { resources: items }
      end
    

    相关文章

      网友评论

          本文标题:山竹记账-环境搭建

          本文链接:https://www.haomeiwen.com/subject/fzyksrtx.html