首页 > 解决方案 > 我应该在哪里创建创建后挂钩

问题描述

我有以下型号:

class Page < ApplicationRecord
  has_one :architecture
end

class Architecture < ApplicationRecord
  belongs_to :page
end

保存新页面后,我需要捕获它的架构(例如段落数)。我想知道这样做的正确方法是什么。我不确定我是否应该让页面模型负责:

class Page < ApplicationRecord
  has_one :architecture

  after_create :scrape_architecture

  private

  def scrape_architecture
    data = call_something_to_capture_architecture(url)
    create_architecture(data)
  end
end

class Architecture < ApplicationRecord
  belongs_to :page
end

或者如果它应该是架构模型的责任:

class Page < ApplicationRecord
  has_one :architecture

  after_create :create_architecture
end

class Architecture < ApplicationRecord
  belongs_to :page

  before_create :scrape_page

  private

  def scrape_page
    data = call_something_to_capture_architecture(page.url)
    create(data)
  end
end

这实际上是错误的,因为before_create在验证之后运行 - 由于非空约束导致 MySQL 错误

谢谢你。

标签: ruby-on-railsruby

解决方案


我只会创建一个处理抓取的作业服务对象

class PageScrapingJob < ApplicationJob
  queue_as :default

  def perform(page)
    data = call_something_to_capture_architecture(page.url)
    architecture = page.create_actitecture(data)
    # ...
  end
end

保存页面后,您将在控制器中调用服务/作业:

class PagesController < ApplicationController
  def create 
    @page = Page.new(page_params)
    if @page.save
      PageScrapingJob.perform_now(@page)
      redirect_to @page
    else
      render :new
    end
  end
end

这使您可以完美地控制何时触发,并避免将更多责任置于模型上。即使您的模型可能包含很少的代码,它们也有大量的职责,例如 ActiveModel 和 ActiveRecord 提供的验证、I18n、表单绑定、脏跟踪等。这个名单真的很长。

相反,这会创建一个离散对象,它只完成一项工作(并且希望做得很好),并且可以独立于控制器进行测试。


推荐阅读