比较两个列表并根据差异同步数据库

时间:2014-04-30 04:35:25

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

我有以下资源关系:

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中可以有多个具有相同位置的路线(在不同的轨道中)。

1 个答案:

答案 0 :(得分:0)

我找到了解决方案。我会在这里发布我的代码,以防它帮助其他任何人。

我的控制器中有这个方法来处理来自前端的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宝石真的有助于保持正确的位置。但是,当我将其包含在我的模型中时,我确实必须限制其范围,以确保它仅在具有特定track_id的关系(TrackCourses)上运行。