一、 步骤

1. rm Gemfile.lock
2. bundle update
3. rails app:update

二、 说明

1. dockerfile

第一步构建,需要下载安装 oracle, 后续在第一步镜像上构建

dockerfile 如下:

FROM ruby:2.7.2
ENV RAILS_ROOT /var/www/research
ENV port 3000
ENV RAILS_ENV production
ENV LD_LIBRARY_PATH=/opt/oracle/instantclient_11_2
EXPOSE $port:$port/tcp
WORKDIR $RAILS_ROOT

RUN cd / && rm -rf $RAILS_ROOT

COPY . .

RUN mv vendor/sources.list /etc/apt/sources.list && \
    apt-get update &&     apt-get install -y  libpq-dev libaio1 &&\
    cd /opt && curl -O http://rccdevops.oss-cn-hangzhou.aliyuncs.com/oracle.zip && unzip oracle.zip && rm -rf oracle.zip &&\
    cp /usr/share/zoneinfo/Asia/Shanghai  /etc/localtime &&\
    curl -O http://rccdevops.oss-cn-hangzhou.aliyuncs.com/utils/rcc-confd &&\
    chmod +x rcc-confd &&\
    cp /usr/share/zoneinfo/Asia/Shanghai  /etc/localtime &&\
    mkdir -p $RAILS_ROOT/tmp/pids/ &&\
    mkdir -p $RAILS_ROOT/tmp/sockets/ &&\
    mkdir -p $RAILS_ROOT/log &&\
    bundle 
CMD ./rcc-confd

2. deployment.yml

Could not find rake
  • gems 安装到 /usr/local/bundle/gems 下

  • pod 里取的是 /usr/local/bundle/ruby/2.7.2/gems 下的 gems

  • 删除 BUNDLE_PATH

  • 添加 GEM_PATH /usr/local/bundle

这是 ruby 版本升级和 bundle 的原因

参考: https://github.com/docker-library/ruby/pull/306

deployment.yml 配置文件如下:

apiVersion: apps/v1beta2
kind: Deployment
metadata:
  labels:
    app: research
  name: research
spec:
  progressDeadlineSeconds: 600
  replicas: POD_REPLICAS
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: research
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: research
    spec:
      containers:
        - env:
            - name: LANG
              value: C.UTF-8
            - name: RUBY_MAJOR
              value: '2.7'
            - name: RUBY_DOWNLOAD_SHA256
              value: 9bf6370aaa82c284f193264cc7ca56f202171c32367deceb3599a4f354175d7d
            - name: GEM_HOME
              value: /usr/local/bundle
            - name: GEM_PATH
              value: /usr/local/bundle
            - name: BUNDLE_SILENCE_ROOT_WARNING
              value: '1'
            - name: BUNDLE_APP_CONFIG
              value: /usr/local/bundle
            - name: RAILS_ROOT
              value: /var/www/research
            - name: LD_LIBRARY_PATH
              value: /opt/oracle/instantclient_11_2
            - name: port
              value: '3000'
            - name: RAILS_ENV
              value: production
            - name: CONFD_ENV
              valueFrom:
                configMapKeyRef:
                  key: CONFD_ENV
                  name: resource
            - name: CONFD_RUN
              value: puma -C config/puma.rb
            - name: aliyun_logs_research
              value: /var/www/research/log/*.log
          securityContext:
            privileged: true
          image: 'registry-vpc.cn-hangzhou.aliyuncs.com/rcc_image/research:IMAGE_TAG'
          imagePullPolicy: Always
          name: research
          resources:
            limits:         #最高运行限制
              cpu: 500m   #容器启动后最多可用CPU核数。
              memory: 3000Mi  #容器启动最多可用内存数 单位MiB、GiB
            requests:       #最低启动限制设置
              cpu: 100m  #最低容器启动可用CPU核数。
              memory: 2244Mi  #最低容器启动可用内存数 单位MiB、GiB
          terminationMessagePath: /dev/termination-log
          terminationMessagePolicy: File
          volumeMounts:
            - mountPath: /var/www/research/public/download
              name: volume-pangu-download
            - mountPath: /var/www/research/public/files
              name: volume-reach-files
      dnsPolicy: ClusterFirst
      imagePullSecrets:
        - name: dev
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
      nodeSelector:
        group: oms
      volumes:
        - name: volume-pangu-download
          persistentVolumeClaim:
            claimName: pangu-download
        - name: volume-reach-files
          persistentVolumeClaim:
            claimName: reach-files

3. undefined Rack::Protection

6.1.0
Web UI - Dark Mode fixes [#4543, natematykiewicz]
Ensure Rack::ContentLength is loaded as middleware for correct Web UI responses [#4541]
Avoid exception dumping SSL store in Redis connection logging [#4532]
Better error messages in Sidekiq::Client [#4549]
**Remove rack-protection, reimplement CSRF protection [#4588]**
Require redis-rb 4.2 [#4591]
Update to jquery 1.12.4 [#4593]
Refactor internal fetch logic and API [#4602]

注释如下配置:

# Sidekiq::Web.class_eval do
#   use Rack::Protection, origin_whitelist: ['http://research.rccchina.com', 'https://research.rccchina.com'] # resolve Rack Protection HttpOrigin
# end if Rails.env.production?

4. ActiveRecord::UnknownAttributeReference

ActiveRecord::UnknownAttributeReference (Query method called with non-attribute argument(s): "projects.urgent desc, projects.reject, project_messages.submit_at "):
order_sql = 'projects.urgent desc, projects.reject, project_messages.submit_at '

因为 order 后面的参数前后不能有空格, 也不能用函数,比如 NVL(projects.urgent, 0) desc

去除前后空格,函数使用,用 Arel.sql(‘NVL(projects.urgent, 0) desc’)

order(Arel.sql('NVL(projects.urgent, 0) desc'))

5. update_attributes

remark = ReachRemark.where(remark_type: obj_type, type_id: obj_id).last
remark ||= ReachRemark.new(remark_type: obj_type, type_id: obj_id)
if remark.update_attributes(remark: remarks)
  remark.remark
else
  errors.add(:remarks, :invalid, message: '保存失败')
end
NoMethodError (undefined method `update_attributes' for #<ReachRemark:0x00007fc79db87e70>
Did you mean?  update_attribute):
Remove deprecated `ActiveRecord::Base#update_attributes` and `ActiveRecord::Base#update_attributes!`.

全部改为 update

6. Grape

undefined method translate_attribute for #<Grape::Exceptions::ValidationErrors:0xxxxx>

translate_attribute 已经删除, 只有 translate_attributes

7. ActiveModel

# FrozenError: can't modify frozen Hash: {}
errors.details.delete(attr.to_sym) # 这行报错

原因是:

errors.details.freeze # 不能被修改

源代码如下:

module ActiveModel
  class Errors
    class DeprecationHandlingDetailsHash < SimpleDelegator
      def initialize(details)
        details.default = []
        details.freeze
        super(details)
      end
    end

    def details
      hash = group_by_attribute.transform_values do |errors|
        errors.map(&:details)
      end
      DeprecationHandlingDetailsHash.new(hash)
    end
  end
end

参考:https://github.com/rails/rails/blob/6-1-stable/activemodel/CHANGELOG.md

8. utf-8

ActiveRecord::StatementInvalid: Encoding::UndefinedConversionError: "\xE5" from ASCII-8BIT to UTF-8

导入文件,文件名字

"\xE5\xBC\x80\xE5\x8F\x91\xE5\x95\x86\xE5\xAE\xA2\xE6\x88\xB7\xE8\xB5\x84\xE6\xBA\x90\xE4\xB8\x8A\xE4\xBC\xA0_20210105115722.xlsx"

# 使用 force_encoding('utf-8') 方法

转为 “开发商客户资源上传_20210105115722.xlsx”


总结:

Rails 6.1 升级须知:

  • update_attributes 和 update_attributes! 这个方法不能用了
    Remove deprecated `ActiveRecord::Base#update_attributes` and `ActiveRecord::Base#update_attributes!`.
    

    具体文档:https://github.com/rails/rails/blob/6-1-stable/activerecord/CHANGELOG.md

  • Order SQL 前后不允许有空格, 也不允许直接写函数
  • 比如:
    a. Project.order('created_at desc ') # Error
    b. Project.order(' created_at desc') # Error
    c. Project.order('created_at desc') # success
    d. Project.order(Arel.sql(' created_at desc ')) # success
    e. Project.order('NVL(projects.urgent, 0) desc') # Error
    f. Project.order(Arel.sql('NVL(projects.urgent, 0) desc')) # success
    

推荐使用:Project.order(created_at: :desc, updated_at: :desc) 的形式 如果非要嵌入字符串,可以使用 Arel.sql() 包装一下,用 Arel.sql, Rails 就认为你这个字符串是安全的,并不会做 Rails 安全检查, 必须格外小心使用

具体文档:https://github.com/rails/rails/blob/master/activerecord/lib/arel.rb

遗留问题:

  • scope
  • where.not
  • can’t modify frozen attributes
  • ActiveRecord::Base.has_many_inversing = true