You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Ruby on Rails中通过OOP方式合并department与person的CSV数据

Ruby on Rails 多CSV合并OOP实现方案

1. 定义基础领域类

首先明确Department和Person的职责,只封装自身属性和相关业务方法:

# app/models/department.rb
class Department
  attr_reader :name, :students, :teachers

  # 支持默认空数组传入students、teachers参数
  def initialize(name, midterm_score_ratio, final_score_ratio, minimum_passing_score, university_name, students = [], teachers = [])
    @name = name
    @midterm_score_ratio = midterm_score_ratio.to_f
    @final_score_ratio = final_score_ratio.to_f
    @minimum_passing_score = minimum_passing_score.to_i
    @university_name = university_name
    @students = students
    @teachers = teachers
  end

  def print_department_name
    puts "院系名称:#{@name}"
  end

  # 其他院系相关业务方法可在这里扩展
end
# app/models/person.rb
class Person
  attr_reader :name, :role, :department_name

  def initialize(name, role, department_name, **other_attributes)
    @name = name
    @role = role # 字段值约定为 student 或 teacher
    @department_name = department_name
    # 学号、工号等其他属性可自行扩展接收
  end
end

如果需要区分学生、教师的不同行为,可以继承Person生成Student、Teacher子类。

2. 封装CSV合并导入服务

遵循单一职责原则,单独封装服务类处理CSV读取、数据关联逻辑,不要和领域类逻辑耦合:

# app/services/csv_merger_service.rb
require 'csv'

class CsvMergerService
  def initialize(department_csv_path, person_csv_path)
    @department_csv_path = department_csv_path
    @person_csv_path = person_csv_path
    # 人员分组缓存结构:{ "数学系" => { students: [], teachers: [] } }
    @person_group_cache = {}
  end

  # 对外暴露的执行入口,返回所有关联完成的Department实例数组
  def execute
    load_and_group_persons
    load_departments_with_persons
  end

  private

  # 先读取所有人员数据,按院系+角色分组缓存,避免重复遍历
  def load_and_group_persons
    CSV.foreach(@person_csv_path, headers: true) do |row|
      person = Person.new(
        row["name"],
        row["role"],
        row["department_name"]
        # 其他CSV字段按需传入即可
      )
      # 初始化对应院系的分组容器
      @person_group_cache[person.department_name] ||= { students: [], teachers: [] }
      # 按角色归类
      if person.role == "student"
        @person_group_cache[person.department_name][:students] << person
      elsif person.role == "teacher"
        @person_group_cache[person.department_name][:teachers] << person
      end
    end
  end

  # 读取院系CSV,直接从缓存取对应人员生成实例
  def load_departments_with_persons
    departments = []
    CSV.foreach(@department_csv_path, headers: true) do |row|
      # 没有对应人员的院系默认返回空数组
      dept_persons = @person_group_cache.fetch(row["name"], { students: [], teachers: [] })
      department = Department.new(
        row["name"],
        row["midterm_score_ratio"],
        row["final_score_ratio"],
        row["minimum_passing_score"],
        row["university_name"],
        dept_persons[:students],
        dept_persons[:teachers]
      )
      department.print_department_name
      departments << department
    end
    departments
  end
end

3. 调用示例

直接替换你原来的CSV读取逻辑即可:

dept_csv_path = "#{__dir__}/../csv/department.csv"
person_csv_path = "#{__dir__}/../csv/person.csv"
# 执行后拿到所有关联完成的院系实例
all_departments = CsvMergerService.new(dept_csv_path, person_csv_path).execute

扩展说明

  • 如果是Rails ActiveRecord持久化场景,把领域类的new方法替换为find_or_initialize_by/create即可,整体逻辑不需要修改
  • 后续如果要新增其他CSV关联、调整字段映射规则,只需要修改对应服务类方法,不需要改动业务逻辑代码
  • 结构可测试性高:可以单独给服务类写单元测试,模拟CSV输入验证关联逻辑是否正确

内容的提问来源于stack exchange,提问作者Alper Efe Sahin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 18:30:06