Ruby on Rails循环实现:影院XML电影数据与数据库同步求助
Hey there! 作为Ruby/Rails新手,你要的同步逻辑其实可以拆成几个简单的步骤,我直接给你可运行的代码,再一步步讲清楚每个部分的作用,保证你能快速搞定~
完整同步代码
把这段代码放到你的Rails项目里(比如可以写在app/services/movie_sync_service.rb里,或者直接在控制台测试):
require 'open-uri' require 'nokogiri' def sync_movies_with_xml begin # 1. 从XML获取最新电影标题列表 xml_url = "http://www.kinoballada.info/repertuar/export/small/dzien/xml" doc = Nokogiri::XML(open(xml_url)) # 提取所有标题并去除首尾空格,避免匹配误差 xml_movie_titles = doc.css('dzien tytul').map { |node| node.inner_text.strip } # 2. 获取数据库中现有电影的标题列表 db_movie_titles = Movie.pluck(:name).map(&:strip) # 3. 新增XML中有但数据库没有的电影 new_titles = xml_movie_titles - db_movie_titles new_titles.each do |title| Movie.create!(name: title) puts "✅ 新增电影: #{title}" end # 4. 删除数据库中有但XML没有的电影 movies_to_remove = Movie.where.not(name: xml_movie_titles) movies_to_remove.each do |movie| puts "❌ 删除电影: #{movie.name}" movie.destroy end puts "\n🎉 同步完成!当前数据库共有 #{Movie.count} 部电影" rescue => e puts "⚠️ 同步出错啦: #{e.message}" end end # 调用方法执行同步 sync_movies_with_xml
分步解释
我把逻辑拆成了4个核心步骤,每个步骤都做了适配新手的优化:
- 提取XML标题:用
css('dzien tytul')直接定位到每个电影的标题节点,strip()是关键——避免因为XML里的空格、换行导致“同名但不匹配”的问题(比如XML里是" 流浪地球2 ",数据库里是"流浪地球2",不加strip会被当成两个不同的标题)。 - 获取数据库标题:用
pluck(:name)比查询所有Movie对象更高效,只取出我们需要的标题字段,同样做strip处理保持格式一致。 - 新增电影:通过数组差集
xml_movie_titles - db_movie_titles快速得到需要新增的标题,用create!而不是create是为了如果创建失败(比如数据库有必填字段没填)会直接抛出错误,方便你排查问题。 - 删除过期电影:用
where.not(name: xml_movie_titles)一次性找出所有需要删除的电影,遍历输出日志方便你核对,如果你不需要日志,可以直接用Movie.where.not(name: xml_movie_titles).destroy_all更高效。 - 异常处理:用
begin-rescue包裹整个逻辑,就算XML网站临时宕机或者网络出问题,程序也不会崩溃,还会告诉你出错原因。
实现每日自动同步(可选)
如果要每天自动执行这个同步,推荐用Rake任务配合系统Cron:
- 在
lib/tasks/movie_sync.rake里创建任务:
namespace :movies do desc "同步数据库与影院XML电影数据" task sync: :environment do sync_movies_with_xml end end
- 用系统Cron定时触发(比如每天凌晨2点执行):
打开终端输入crontab -e,添加一行:
0 2 * * * cd /你的Rails项目绝对路径 && bundle exec rake movies:sync >> log/movie_sync.log 2>&1
这样每天凌晨2点就会自动同步,日志会存在log/movie_sync.log里方便查看。
内容的提问来源于stack exchange,提问作者Ins0maniac
相关产品推荐
相关产品推荐

