Rails 单图片上传与删除

学生图片上传(StudentPhoto)

  1. 在路由 routes.rb 添加上传方法 uploadFile
	resources :student_photos do
        member do
          # 上传图片
          post :uploadFile
        end
    end
  1. view -》 StudentPhoto -》form.html
    <div class="col-sm-3" style="margin-top: 20px;">
      <div class="img_border">
        <div class="img_plus">+</div>
        <div class="img_bt">点击上传</div>
        <canvas id="canvas" style="position:absolute;" class="form-group">
        </canvas>
        <%= file_field 'student','image',class: "upload", id: "file_btn" %>
      </div>
    </div>
    <%= f.submit "提交", data:{:disable_with => '提交中...'}, :class => "base_bt"%>

css 图片框的样式

.img_border{
  position:relative;
  height: 200px;
  width:172px;
  border-radius: 10px;
  border:1px dashed rgba(197,208,219,1);
}
.img_plus{
  position:absolute;
  top:0;
  bottom: 0;
  margin: auto 0;
  width: 100%;
  text-align: center;
  font-size:50px;
  font-family:Microsoft YaHei;
  font-weight:400;
  color:rgba(197,208,219,1);
  display: flex;
  align-items: center;
  justify-content: center;
}
.img_bt{
  position:absolute ;
  bottom:0;
  font-size:16px;
  font-family:Microsoft YaHei;
  font-weight:300;
  color:rgba(255,255,255,1);
  background:rgba(153,153,153,1);
  height:24px;
  text-align: center;
  line-height:30px;
  border-bottom-left-radius: 5px;
  border-bottom-right-radius: 5px;
  width: 170px;
  height: 30px;
}
.upload{
  height: 200px;
  width: 170px;
  font-size: 100px;
  /* 设置透明度 */
  opacity: 0;
  filter:alpha(opacity=0);
  cursor:pointer;
}

script 部分代码

<script type="text/javascript">
  let file_btn = document.getElementById('file_btn');
  let canvas = document.getElementById('canvas');
  
  // 给定canvas在页面的占位,图片大于则宽高等比例缩小
  canvas.width = 170;
  canvas.height = 200;
  
  // 1.监听文件上传按钮的选择文件的事件
  file_btn.addEventListener("change", function () {
    let data_url = file_btn.files[0];
    console.log(data_url);
    
    // 2.使用FileReader类来读取文件内容
    let reader = new FileReader();
    reader.readAsDataURL(data_url);
    
    // 3.监听FileReader读取器读取完成事件(此事件后才可以获取到文件内容,进行图片渲染或上传)
    reader.onload = function () {
    
      // 3.1 异步渲染(canvas)
      let cxt = canvas.getContext('2d');
      let img = new Image();
      img.src = this.result;
      
      // 3.11 Image对象数据准备完成事件
      img.onload = function () {
        cxt.clearRect(0, 0, canvas.width, canvas.height);// 清空上一次的图片
        // 绘画
        let width = img.width;
        let height = img.height;
        let result = geometric_scaling(width, height, canvas.width, canvas.height);
        if (result['scale_by'] === 'none') {
            cxt.drawImage(img, (canvas.width - result['width']) / 2, (canvas.height - result['height']) / 2, result['width'], result['height'])
        }
        if (result['scale_by'] === 'width') {
            cxt.drawImage(img, 0, (canvas.height - result['height']) / 2, result['width'], result['height'])
        }
        if (result['scale_by'] === 'height') {
            cxt.drawImage(img, (canvas.width - result['width']) / 2, 0, result['width'], result['height'])
        }

      }
      
      // 3.2.异步上传(ajax) param = {"img":this.result}(数据格式为base64)
    }
  });
  
  // 封装等比缩小的方法
  function geometric_scaling(image_width, image_height, canvas_width, canvas_height) {
    let width = image_width;
    let height = image_height;
    let scale = 1;
    let scale_by = 'none';
    let return_data = {width, height, scale, scale_by};
    if (image_height < canvas_height && image_width < canvas_width) {
        return return_data
    } else if (image_height > canvas_height && image_width > canvas_width) {
    
        // 都大
        let scale_height = canvas_height / image_height;
        let scale_width = canvas_width / image_width;
        if (scale_height < scale_width) {
            scale = scale_height;
            scale_by = 'height';
        } else {
            scale = scale_width;
            scale_by = 'width';
        }
    }
    
    // 不是都小也不是都大的剩下两种情况
    else if (image_height > canvas_height) {
        scale = canvas_height / image_height;
        scale_by = 'height';
    } else {
        scale = canvas_width / image_width;
        scale_by = 'width';
    }
    return_data['width'] = image_width * scale;
    return_data['height'] = image_height * scale;
    return_data['scale'] = scale;
    return_data['scale_by'] = scale_by;
    return return_data
  }

</script>
  1. 在 student_photos_controller.rb ,添加 uploadFile 方法
    观看方法顺序:create -》uploadFile -》getFileName
    class StudentPhotosController < ApplicationController

      # 上传图片
      def uploadFile(file, id)
        if !file.original_filename.empty?
          # 生成一个文件名  随机+时间+格式
          # 路径:upload/student/ + 学生id + 文件名
          # mime = file.content_type
          # ext 为上传文件类型后缀
          ext = file.original_filename.split(".")[-1]  # .pop()
          @filename = getFileName(id, file.original_filename, ext)
          # 判断文件是否存在,不存在则创建一个以学号命名的文件夹
          afile = "#{Rails.root}/public/upload/student/#{id}"
          FileUtils.mkdir_p(afile) unless File.exists?(afile)

          # 向目录写入文件
          File.open(Rails.root.join(afile, @filename), "wb") do |f|
            f.write(file.read)
          end
          # 返回文件名称,保存到数据库中
          return @filename
        end
      end

      def getFileName(id, filename,ext)
        if !filename.nil?
          # 防止新文件名重复
          # 生成安全的base64字符串
          key = SecureRandom.urlsafe_base64
          # 'upload/student/'+ id.to_s + '/' +
          name = key.to_s + 't' + Time.now.strftime("%y%m%d%I%M%S") + '.' + ext.to_s
          filename.sub(/.*./, name)
        end
      end

      def new
        @student_photo = ::Student.new
      end

      def create
        @student_photo = ::Student.new(student_photo_params)
        if !params[:student]['image'].blank?
          uploadFile(params[:student]['image'],@student_photo.student_code)
        end
        
        if @student_photo.save
          flash[:notice] = "学生图片保存成功"
          redirect_to admin_student_student_photos_path
        else
          flash[:error] = @student_photo.errors.full_messages.uniq.join(', ')
          redirect_to new_admin_student_student_photo_path
        end
      end

      def update
       
      end

      private
      def find_student_id
        @student_photo = ::Student.find(params[:id])
      end

      def student_photo_params
        params.require(:student).permit(:student_code)
      end
      
    end

实现效果如下图片框:

在这里插入图片描述

编辑学生图片(显示、上传与删除)

  1. 在路由 routes.rb 添加以下方法
    删除图片 delete_simple_student_photo
    显示图片 all_student_photo
	resources :student_photos do
        member do
          # 上传图片
          post :uploadFile
        end
        collection do
          # 删除单张图片
          post :delete_simple_student_photo
          # 获取学生人脸图片
          get :all_student_photo
        end
      end
  1. view -》 StudentPhoto -》edit.html
	<div class="pic" style="border: none;">
        <div class="img_border">
          <div class="img_plus">+</div>
          <canvas id="canvas" style="position:absolute;" class="form-group"></canvas>
          <%= file_field 'student', 'image', class: "upload", id: "file_btn" %>
        </div>
	</div>
	<%= f.submit "提交", data: {:disable_with => '提交中...'}, :class => "base_bt" %>

script 部分代码

<script type="text/javascript">

    // 获取该学生所有照片的路径,并循环插入到相册中
    $.ajax({
        type: "GET",
        url: "/student_photos/all_student_photo?id=<%= @student_photo.student_code %>",
        dataType: "json",
        // 请求成功
        success: function (result) {
            // 取出图片地址的数组
            let pic_file = result.pic_file;
            for (i = 0; i < pic_file.length; i++) {
                  $("#pic_div").append("<div class=\"pic_list\"><img id=\"show" + i + "\" class=\"pic\" src=\"" + pic_file[i] + "\">" +
                      "<i class=\"delImg\" οnclick='delImg(\"" + pic_file[i] + "\")'>X</i></div>");
                <% else %>
                  $("#pic_div").append("<div class=\"pic_list\"><img id=\"show" + i + "\" class=\"pic\" src=\"" + pic_file[i] + "\">" +
                      "</div>");
                <% end %>
              console.log(pic_file[i])
            }
        },
        // 请求失败,包含具体的错误信息
        error: function (e) {
            console.log(e.status);
            console.log(e.responseText);
            alert("照片墙加载失败,请与管理员联系");
        }
    });

    function delImg(msg){
        var m = confirm("确定删除该照片?")
        if(m == true){
            $.ajax({
                type: "POST",
                url: "/student_photos/delete_simple_student_photo",
                data: {msg: msg},
                dataType: "json",
                // 请求成功
                success: function (result) {
                    let del = result.pic
                    alert(del)
                    history.go(0)
                },
                // 请求失败,包含具体的错误信息
                error: function (e) {
                    console.log(e.status);
                    console.log(e.responseText);
                    alert("删除图片失败,请与管理员联系");
                }
            });
        }else{
            alert("删除图片失败,请与管理员联系")
        }
    }

    let file_btn = document.getElementById('file_btn');
    let canvas = document.getElementById('canvas');
    // let pic = document.getElementById('pic');
    // 给定canvas在页面的占位,图片大于则宽高等比例缩小
    canvas.width = 170;
    canvas.height = 200;


    file_btn.addEventListener("change", function () {
        let data_url = file_btn.files[0];
        console.log(data_url);
        // 2.使用FileReader类来读取文件内容
        let reader = new FileReader();
        reader.readAsDataURL(data_url);
        // 3.监听FileReader读取器读取完成事件(此事件后才可以获取到文件内容,进行图片渲染或上传)
        reader.onload = function () {
            // 3.1 异步渲染(canvas)
            let cxt = canvas.getContext('2d');
            let img = new Image();
            img.src = this.result;
            // 3.11 Image对象数据准备完成事件
            img.onload = function () {
                cxt.clearRect(0, 0, canvas.width, canvas.height);// 清空上一次的图片
                // 绘画
                let width = img.width;
                let height = img.height;
                let result = geometric_scaling(width, height, canvas.width, canvas.height);
                if (result['scale_by'] === 'none') {
                    cxt.drawImage(img, (canvas.width - result['width']) / 2, (canvas.height - result['height']) / 2, result['width'], result['height'])
                }
                if (result['scale_by'] === 'width') {
                    cxt.drawImage(img, 0, (canvas.height - result['height']) / 2, result['width'], result['height'])
                }
                if (result['scale_by'] === 'height') {
                    cxt.drawImage(img, (canvas.width - result['width']) / 2, 0, result['width'], result['height'])
                }

            }
            // 3.2.异步上传(ajax) param = {"img":this.result}(数据格式为base64)
        }
    });

    // 封装等比缩小的方法
    function geometric_scaling(image_width, image_height, canvas_width, canvas_height) {
        let width = image_width;
        let height = image_height;
        let scale = 1;
        let scale_by = 'none';
        let return_data = {width, height, scale, scale_by};
        if (image_height < canvas_height && image_width < canvas_width) {
            return return_data
        } else if (image_height > canvas_height && image_width > canvas_width) {
            // 都大
            let scale_height = canvas_height / image_height;
            let scale_width = canvas_width / image_width;
            if (scale_height < scale_width) {
                scale = scale_height;
                scale_by = 'height';
            } else {
                scale = scale_width;
                scale_by = 'width';
            }
        }
        // 不是都小也不是都大的剩下两种情况
        else if (image_height > canvas_height) {
            scale = canvas_height / image_height;
            scale_by = 'height';
        } else {
            scale = canvas_width / image_width;
            scale_by = 'width';
        }
        return_data['width'] = image_width * scale;
        return_data['height'] = image_height * scale;
        return_data['scale'] = scale;
        return_data['scale_by'] = scale_by;
        return return_data
    }
</script>

css 图片显示和删除按钮样式

  .pic_list{
    width: 100%;
    height: 100%;
    padding-bottom: 0%;
    position: relative;
    overflow: hidden;
  }
  .delImg {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: gray;
    color: white;
    position: absolute;
    right: 12px;
    top: 12px;
    z-index: 2;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: .9 ;
    cursor: pointer;
  }
  .delImg:hover{
    background: red;
    color: white;
    opacity: .9;
  }
  1. 在 student_photos_controller.rb ,添加显示与删除图片方法
class StudentPhotosController < ApplicationController
		
	   # 显示学生全部图片
      def all_student_photo
        file_path = "/upload/student/#{params[:id]}"
        pic_file = []
        if File.directory?("#{Rails.root}/public#{file_path}")
          Dir.foreach("#{Rails.root}/public#{file_path}") do |filename|
            # ruby遍历目录下所有文件时会包含“.”和“..”,这两者都属于目录,需要进行排除
            unless File.directory?(filename)
              pic_file << "#{file_path}" + '/' + filename
            end
          end
        end
        render json: {pic_file: pic_file}
      end

	  #删除单张图片
      def delete_simple_student_photo
        msg = params[:msg]
        File.delete("#{Rails.root}/public/#{msg}")
        pic = "该图片删除成功"
        render json: {pic: pic}
      end
      
      # 上传图片
      def uploadFile(file, id)
        if !file.original_filename.empty?
          # 生成一个文件名  随机+时间+格式
          # 路径:upload/student/ + 学生id + 文件名
          # mime = file.content_type
          # ext 为上传文件类型后缀
          ext = file.original_filename.split(".")[-1]  # .pop()
          @filename = getFileName(id, file.original_filename, ext)
          # 判断文件是否存在,不存在则创建一个以学号命名的文件夹
          afile = "#{Rails.root}/public/upload/student/#{id}"
          FileUtils.mkdir_p(afile) unless File.exists?(afile)

          # 向目录写入文件
          File.open(Rails.root.join(afile, @filename), "wb") do |f|
            f.write(file.read)
          end
          # 返回文件名称,保存到数据库中
          return @filename
        end
      end

      def getFileName(id, filename,ext)
        if !filename.nil?
          # 防止新文件名重复
          # 生成安全的base64字符串
          key = SecureRandom.urlsafe_base64
          # 'upload/student/'+ id.to_s + '/' +
          name = key.to_s + 't' + Time.now.strftime("%y%m%d%I%M%S") + '.' + ext.to_s
          filename.sub(/.*./, name)
        end
      end

      def new
        @student_photo = ::Student.new
      end

      def create
        @student_photo = ::Student.new(student_photo_params)
        if !params[:student]['image'].blank?
          uploadFile(params[:student]['image'],@student_photo.student_code)
        end
        
        if @student_photo.save
          flash[:notice] = "学生图片保存成功"
          redirect_to admin_student_student_photos_path
        else
          flash[:error] = @student_photo.errors.full_messages.uniq.join(', ')
          redirect_to new_admin_student_student_photo_path
        end
      end

      def update
       @student_photo = ::Student.find(params[:id])
        if !params[:student]['image'].blank?
          file_name = uploadFile(params[:student]['image'],@student_photo.student_code)
        end
        
        if @student_photo.update(student_photo_params)
          flash[:notice] = "学生图片修改成功"
          redirect_to edit_admin_student_student_photo_path(@student_photo)
        else
          flash[:error] = @student_photo.errors.full_messages.uniq.join(', ')
          redirect_to edit_admin_student_student_photo_path(@student_photo)
        end
      end

      private
      def find_student_id
        @student_photo = ::Student.find(params[:id])
      end

      def student_photo_params
        params.require(:student).permit(:student_code)
      end
      
    end

实现效果:

在这里插入图片描述

这里主要介绍图片功能的实现,其他不重要的就跳过了。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值