Skip to content

Instantly share code, notes, and snippets.

@jennli
Last active March 16, 2016 21:35
Show Gist options
  • Save jennli/cf2e0af77aebf472b5a5 to your computer and use it in GitHub Desktop.
Save jennli/cf2e0af77aebf472b5a5 to your computer and use it in GitHub Desktop.

Finite State Machine

gem 'aasm'
  • add a aasm state field to the campaign model
g migration add_aasm_state_to_campaigns aasm_state:string:index
  • migration file looks like this:
class AddAasmStateToCampaigns < ActiveRecord::Migration
  def change
    add_column :campaigns, :aasm_state, :string
    add_index :campaigns, :aasm_state
  end
end
  • rake db migrate
  • add the following to the campaign model
include AASM
  # setting the whiny_transitions: false option makes it so that it won't
  # throw an exception when an invalid transition happen
  aasm whiny_transitions: false do
    state :draft, initial: true
    state :published
    state :unfunded
    state :funded
    state :canceled

    event :publish do
      transitions from: :draft, to: :published
    end

    event :cancel do
      transitions from: [:draft, :published, :funded], to: :canceled
    end

    event :fund do
      transitions from: :published, to: :funded
    end

    event :unfund do
      transitions from: :published, to: :unfunded
    end
  end
  • set the transition state
2.2.3 :008 >   c.draft?
true
2.2.3 :009 > c.published?
false
2.2.3 :010 > c.published!
   (0.2ms)  BEGIN
  Campaign Exists (0.4ms)  SELECT  1 AS one FROM "campaigns" WHERE ("campaigns"."name" = 'Hello try reward' AND "campaigns"."id" != 8) LIMIT 1
  SQL (0.3ms)  UPDATE "campaigns" SET "aasm_state" = $1, "updated_at" = $2 WHERE "campaigns"."id" = $3  [["aasm_state", "published"], ["updated_at", "2016-03-16 20:44:09.409139"], ["id", 8]]
  FriendlyId::Slug Load (0.2ms)  SELECT  "friendly_id_slugs".* FROM "friendly_id_slugs" WHERE "friendly_id_slugs"."sluggable_id" = $1 AND "friendly_id_slugs"."sluggable_type" = $2  ORDER BY "friendly_id_slugs".id DESC LIMIT 1  [["sluggable_id", 8], ["sluggable_type", "Campaign"]]
   (1.3ms)  COMMIT
true
2.2.3 :011 >

only show campaigns that are published on the index page

  • have a method in campaign model
def published
    where(aasm_state: :published)
  end
  • now change the index action in controller
def index
    # @campaigns = Campaign.all
    @campaigns = Campaign.order("created_at ASC").published
  end
  • better to create new controller for showing only user's own campaigns
$ rails g controller my_campaigns
  • routes
  resources :my_campaigns, only: [:index]
  • in _header.html.erb, add in a link to only show user's campaigns
<%= link_to "Campaigns", my_campaigns_path %>
  • add in the following view
<% @campaigns.each do |c| %>
<div class="well">
  <%= link_to c.name, c %>
  <p><%= c.description.truncate(100) %></p>
  <% end %>
</div>
  • show campaign's state on campaign show page
<div class="label label-default">
  <%= @campaign.aasm_state %>
</div>

To publish a campaign

  • create a new controller
rails g controller publishings
  • nest publishing routes inside campaigns
  resources :campaigns do
    resources :pledges, only: [:create, :destroy]
    resources :publishings, only: [:create]
  end
  • add a button on campaign show page which will publish this campaign
<% if @campaign.draft? %>
<%= link_to "Publish", campaign_publishing_path(@campaign), method: :post, class: "btn btn-primary", data: {confirm: "are you sure? you won't be able to edit a campaign after it's pubhlished"} %>
<% end %>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment