Benito Serna Tips and tools for Ruby on Rails developers

Did you finish the exercise?… Here is my answer =)

require "rspec"
require "active_model"

module Blog
  def self.new_post_form
    Form.new
  end

  def self.add_post(attrs, store)
    form = Form.new(attrs)

    if form.valid?
      store.create(form.to_h)
      SuccessStatus
    else
      ErrorStatus.new(form)
    end
  end

  def self.list_all_posts(store)
    store.all.sort_by(&:id).reverse
  end

  class Post
    attr_reader :id, :title

    def initialize(attrs)
      @id = attrs[:id]
      @title = attrs[:title]
    end
  end

  class Form
    include ActiveModel::Model
    attr_accessor :title, :body
    validates_presence_of :title

    def to_h
      { title: title, body: body }
    end
  end

  class ErrorStatus
    attr_reader :form

    def initialize(form)
      @form = form
    end

    def success?
      false
    end
  end

  class SuccessStatus
    def self.success?
      true
    end
  end
end

module Blog
  RSpec.describe "Add post" do
    class DummyStore
      def self.create(attrs)
      end
    end

    def new_post_form
      Blog.new_post_form
    end

    def add_post(params, store)
      Blog.add_post(params, store)
    end

    def store
      DummyStore
    end

    it "has a form" do
      form = new_post_form
      expect(form.title).to eq nil
      expect(form.body).to eq nil
    end

    describe "with all attributes..." do
      attr_reader :params

      before do
        @params = { "title" => "P1", "body" => "Super!" }
      end

      it "returns success" do
        status = add_post(params, store)
        expect(status).to be_success
      end

      it "creates a record" do
        expect(store).to receive(:create).with(title: "P1", body: "Super!")
        add_post(params, store)
      end
    end

    describe "without title..." do
      it "does not returns success" do
        status = add_post({}, store)
        expect(status).not_to be_success
      end

      it "does not creates the record" do
        expect(store).not_to receive(:create)
        add_post({}, store)
      end

      it "returns a blank error" do
        status = add_post({}, store)
        expect(status.form.errors[:title]).to eq ["can't be blank"]
      end
    end
  end

  RSpec.describe "List all posts" do
    class FakeStore
      attr_reader :all

      def initialize(records)
        @all = records
      end
    end

    def post_with(attrs)
      Post.new(attrs)
    end

    def store_with(records)
      FakeStore.new(records)
    end

    def list_all_posts(store)
      Blog.list_all_posts(store)
    end

    it "returns all the stored posts" do
      store = store_with([
        post_with(id: 1, title: "Post-1"),
        post_with(id: 2, title: "Post-2")
      ])

      posts = list_all_posts(store)
      expect(posts.count).to eq 2
    end

    it "returns the posts sorted by id in descendent order" do
      store = store_with([
        post_with(id: 1, title: "Post-1"),
        post_with(id: 2, title: "Post-2")
      ])

      posts = list_all_posts(store)
      expect(posts.map(&:id)).to eq [2, 1]
    end

    describe "each post..." do
      it "has some attributes..." do
        store = store_with([post_with(id: 1, title: "Post-1")])
        post = list_all_posts(store).first
        expect(post.id).to eq 1
        expect(post.title).to eq "Post-1"
      end
    end
  end
end

Weekly tips and tools for Ruby on Rails developers

I send an email each week, trying to share knowledge and fixes to common problems and struggles for ruby on rails developers, like How to fetch the latest-N-of-each record or How to test that an specific mail was sent or a Capybara cheatsheet. You can see more examples on Most recent posts or All post by topic.