I would definitely go with a separate class or with a factory that solely represents the concern this campaign encloses.
On top of, I would assume (though not necessary), you could separate the mailchimp related implementation detail under a different class, which simply knows how to deal with it. Your actual code not suppose to know that low level detail.
However, it could be easily reachable through the campaign builder instance. What if you decide something else instead of Mailchimp ?, Just replace the instance with SomethingCampaignBuilder instance.
Based on those thoughts, I would rewrite to the following code -
@user = user
def update_campaign_content(campaign_id, attrs)
@mailchimp_client ||= user.mailchimp
CreateCampaignError = Class.new(StandardError)
UpdateCampaignError = Class.new(StandardError)
attr_reader :user, :campaign_id, :campaign_builder
def self.deliver(user, campaign_builder)
builder = self.new(user, campaign_builder).build
def initialize(user, campaign_builder)
@user = user
@campaign_builder = campaign_builder
@campaign_attributes = user.detail.create_campaign_params
@campaign_content_attributes = user.detail.create_content_params
@campaign_id = campaign_builder.create_campaign(@campaign_attributes)
raise CreateCampaignError unless @campaign_id.present?
updated = campaign_builder
raise UpdateCampaignError unless updated
user = User.find(134)
campaign_builder = MailchimpCampaignBuilder.new(user)