【问题标题】:Comparing two lists and syncronizing the database based on differences比较两个列表并根据差异同步数据库
【发布时间】:2014-04-30 04:35:24
【问题描述】:

我有以下资源关系:

Class Course < ActiveRecord::Base
  has_many :track_courses
  has_many :tracks, through: :track_courses
end

以及 Track 模型内部的镜像关系。连接这些模型的 TrackCourse 表有以下几行:

id:主键

track_id:代表轨道

course_id:代表课程

位置:该轨道内课程的顺序

我想让管理员用户能够通过 ajax 更新每个轨道中的课程。我在前端有一个列表,它作为哈希传递给控制器​​:

front_end_list = { course_id => position }

表示对象及其在前端可排序的位置。

我也在查找该轨道中现有课程的列表:

existing_courses = TrackCourse.where("track_id = ?", track_id).all

目标:比较这两个列表,根据前端列表同步数据库条目。本质上,如果用户将课程 15 插入网页上的位置 2,我需要将该条目插入 TrackCourse 表(如果它不存在)或更新它的位置(如果它存在)。反之亦然。

这样做的最佳方法是什么? ActiveRecord/ActiveRelation 是否为它提供方法?还是我必须自己写点东西?

更新:我发现了一个名为 acts_as_list 的 gem,但它似乎是为 ActiveRecord 表设计的,而不是为 ActiveRelation 设计的。它本质上期望位置值是唯一的,而在 TrackCourse 中可以有多个具有相同位置的课程(在不同的轨道上)。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-4 rails-activerecord


    【解决方案1】:

    我想出了一个解决办法。我会在这里发布我的代码,以防它帮助其他人。

    我的控制器中有这个方法来处理来自前端的 ajax 请求:

    def sort
        track_id = params[:track_id]
    
        courses_in_list = {}
        params[:course].each do |courseid|
            position = params[:course].index(courseid)
            courses_in_list[courseid.to_i] = position
        end
    
        existing_courses_in_track = {}
        TrackCourse.where("track_id = ?", track_id).to_a.each do |track_course|
            existing_courses_in_track[track_course.course_id] = track_course.position
        end
    
        if courses_in_list.length < existing_courses_in_track.length
    
            existing_courses_in_track.each do |courseid, position|
    
                if courses_in_list[courseid].nil?
                    track_course = TrackCourse.where(track_id: track_id, course_id: courseid).first
                    track_course.remove_from_list
                    track_course.destroy!
                end
    
            end
    
        else
    
            if existing_courses_in_track.empty?
                track_course = TrackCourse.new(track_id: track_id, 
                                               course_id: courses_in_list.keys[0])
                track_course.insert_at(courses_in_list.values[0])
                p "first track!"
    
            else
                courses_in_list.each do |courseid, position|
    
                    track_exists = false
                    if !existing_courses_in_track[courseid].nil?
                        track_course_position = existing_courses_in_track[courseid]
                        track_exists = true
                    end
    
                    if !track_exists
                        TrackCourse.new(track_id: track_id, course_id: courseid).insert_at(position)
                    else
                        p "else statement"
                        track_course = TrackCourse.where(track_id: track_id, course_id: courseid).first
                        track_course.update_attribute(:position, position)
                    end
                end
            end
        end
        render :nothing => true
    end
    

    基本上,我正在构建两个哈希,一个基于前端项目列表及其位置,另一个基于数据库课程及其位置。然后我比较它们。如果前端列表较短,则意味着用户删除了一个项目,因此我遍历后端列表,找到多余的项目并将其删除。然后我采用类似的机制将项目添加到列表并重新排序列表。 acts_as_list gem 确实有助于将事物保持在正确的位置。但是,当我将它包含在我的模型中时,我确实必须限制它的范围,以确保它仅在具有特定 track_id 的关系(TrackCourses)上运行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-19
      • 2014-02-26
      • 2020-07-31
      • 2013-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多