Skip to content

Instantly share code, notes, and snippets.

@jennli
Last active March 29, 2016 21:33
Show Gist options
  • Save jennli/6211fae97deec7ac495a to your computer and use it in GitHub Desktop.
Save jennli/6211fae97deec7ac495a to your computer and use it in GitHub Desktop.

Decorator

  • object that inherits from that object that adds more functions, method, etc, to it
gem 'draper', '~> 1.3'
  • generates the decorator for Campaign
bin/rails g decorator Campaign
  • decorator will go to app/decorator folder
  • initially, the file is generated as the following:
class CampaignDecorator < Draper::Decorator
  delegate_all

  # Define presentation-specific methods here. Helpers are accessed through
  # `helpers` (aka `h`). You can override attributes, for example:
  #
  #   def created_at
  #     helpers.content_tag :span, class: 'time' do
  #       object.created_at.strftime("%a %m/%d/%y")
  #     end
  #   end

end
  • in order for decorator file to be loaded in rails console, add this to application.rb
 config.autoload_paths << Rails.root.join("app", "decorators")
  • go to rails console and type c = Campaign.last, then give c a decorator called d using:
2.2.3 :005 >   d = c.decorate
  • which will show:
#<Campaign:0x007ff2a06ab7e8> {
             :id => 8,
           :name => "Hello try reward",
    :description => "hello",
           :goal => 30,
       :end_date => Tue, 15 Mar 2016 20:32:00 UTC +00:00,
     :created_at => Tue, 15 Mar 2016 20:32:51 UTC +00:00,
     :updated_at => Fri, 18 Mar 2016 20:47:31 UTC +00:00,
        :user_id => nil,
           :slug => "hello-try-reward",
          :image => #<ImageUploader:0x007ff2a0681df8 @model=#<Campaign id: 8, name: "Hello try reward", description: "hello", goal: 30, end_date: "2016-03-15 20:32:00", created_at: "2016-03-15 20:32:51", updated_at: "2016-03-18 20:47:31", user_id: nil, slug: "hello-try-reward", image: nil, aasm_state: "funded", address: "142 W Hasting Street", longitude: -123.1086604, latitude: 49.2819605>, @mounted_as=:image>,
     :aasm_state => "funded",
        :address => "142 W Hasting Street",
      :longitude => -123.1086604,
       :latitude => 49.2819605
}
  • in decorator file, put the following :
  def name
    object.name.titlelize
  end
  • then change the find campaign method in the controller:
def find_campaign
    @campaign = Campaign.friendly.find(params[:id]).decorate
  end
  • then remove all titlieze calls in the view

  • another example of deocrator feature is :

  def goal
    # `helpers` (aka `h`)
    h.number_to_currency object.goal
  end
  • generate html tag
  def state_label
    h.content_tag :div, class:"label label-default" do
      object.aasm_state
    end
  end
  • then modify the show
<%= @campaign.state_label %>
<!-- <div class="label label-default">
  <%= @campaign.aasm_state %>
</div> -->

Service Object

  • create a file "publish_campaign.rb" under app/services/campaigns
class Campaigns::PublishCampaign
  # only call can be a public method
  def call
  end
end
  • use a virtus gem to pass in param when creating object
gem "virtus"
  • then the service file should be changed to:
class Campaigns::PublishCampaign
include Virtus.model
attribute :campaign, Campaign
  # only call can be a public method
  def call
  end
end
  • then implement the call function to handle the publish
  def call
    if campaign.publish!
      DetermineCampaignStateJob.set(wait_until: campaign.end_date).perform_later(campaign)
      true
    else
      false
    end
  end
  • the create action in publish controller will look like this:
def create
    campaign = current_user.campaigns.friendly.find params[:campaign_id]
    service = Campaigns::PublishCampaign.new(campaign: campaign)
    if service.call
      redirect_to campaign, notice: "Published!"
    else
      redirect_to campaign, alert: "Can't publish! Published already?"
    end
  end

refactor create campaign

  • give a service class called CreateCampaign
class Campaigns::CreateCampaign
  include Virtus.model

  attribute :params, Hash
  attribute :user, User
  # this is the campaign that gets created, we may need it for things such as rebuilding teh form with errors
  attribute :campaign, Campaign


  def call
    @campaign = Campaign.new(params)
    @campaign.user = user
    @campaign.save
  end

end
  • adjust the controller create action
def create
    service = Campaign::CreateCampaign.new(user: current_user, params: campaign_params)

    if service.call
      campaign = service.campaign
      flash[:notice] = "campaign created"
      redirect_to campaign_path(campaign)
    else
      build_associated_rewards
      flash[:alert] = "campaign did not get created"
      render :new
    end
  end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment