Building a Ruby on Rails MVP.
Tags: webdev, rails, startup
Published: 2024-05-24 15:18:44

Hey there :wave:,

It's been 2 weeks since I announced the new project I'm working on: [HomeSuiteApartment](https://homesuiteapartment.com), a tool to manage properties.

Today, I'll be sharing an update update on the progress so far, what's next, and share some developer insights for your own Ruby on Rails project! If you'd prefer, I've also uploaded a [video walking through the product](https://youtu.be/3Q--P6-dtO4).

## Progress made so far

I've been able to build out:
- an integration with Stripe to offer subscription plans
- CRUD routes for buildings and units
- CRUD routes to list a unit (at the moment only on HomeSuiteApartment, eventually on other rental listing marketplaces) and send inquiries

A lot of the pages have placeholder content at the moment, which I'll be fleshing out, but the intended workflow is almost done.


![Subscription overview page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pdn4d8dukwg8w6vuot2t.png)

![Buildings index page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fsbn0cx2m24xscjjk70m.png)

![New building page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oi69euyx0djyj0cccyzg.png)

![New building page with validation errors](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/szy7zexj90qd6e6gjr2c.png)

![Unit show page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xzhf8xmmjp7iqecxb4gl.png)

![Unit listing show page, from the admin](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ic9wfo8bvwr7d4n71eg5.png)

![Unit listing show page, viewed by the public](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cppe0g3rszaf86d9fwfo.png)

![New inquiry page](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/12uttwoxhuucxhcs1qq8.png)

## An overview on my workflow

[Ruby on Rails](https://rubyonrails.org/), in my opinion, is the most productive full-stack web framework to-date.

I'd highly recommend reading up on the [Rails Doctrine](https://rubyonrails.org/doctrine), it really explains why Ruby on Rails came to be what it is today and how it's surpassed other frameworks.

---

To get started with Ruby on Rails, it was as simple as generating a new project, using the `rails` command line.

```shell
gem install rails
```

```shell
rails new homesuiteapartment
```

from there, it's as simple as using the provided [generators](https://guides.rubyonrails.org/generators.html) to scaffold the app.

```shell
bin/rails generate scaffold building name
```

This generates a database migration, model, route definition, controller and views, as well as tests if you've configured that. In all of a few minutes, you've got a 'working' application. In most cases, you'll need to do more, but the scaffold generator alone seems like cheating.

One of my favourite things about using generators, is that it's quite easy to customize, especially if you've implemented other gems for authorization and need to change the controller template.

---

Thankfully, [Ruby](https://www.ruby-lang.org/en/) and [Ruby on Rails](https://rubyonrails.org/) are well established, and have a large community building 'packages', known as [gems](https://guides.rubygems.org/what-is-a-gem/), similar to node packages.

[Ruby on Rails](https://rubyonrails.org/) is really just a collection of Gems which work very well together, such as [ActiveRecord](https://github.com/rails/rails/tree/main/activerecord), [ActiveModel](https://github.com/rails/rails/tree/main/activemodel), [ActionView](https://github.com/rails/rails/tree/main/actionview) and much more.

Gems are a helpful tool to easily add new functionality to your Ruby on Rails application, and is especially helpful when building an MVP so you don't need to build everything from scratch.

### Some of my favourite gems

#### Authentication

As mentioned in my previous blog post, [On the road to ramen profitability 🍜 💸](https://dev.to/joelzwarrington/on-the-road-to-ramen-profitability-21fc), I mentioned that I'm using [devise](https://github.com/heartcombo/devise). It's one of the most popular open-source authentication solutions for Rails.

I highly recommend it, as it's very configurable, and there are many plugins which I'll implement in the future, such as [OmniAuth](https://github.com/omniauth/omniauth).

One pitfall though, if you've never worked with Ruby on Rails, I recommend avoiding it and starting with a simple authentication system from scratch.

#### Authorization

If you're unfamiliar with authorization, it's very different from authentication. Read the [Authentication vs. Authorization article](https://auth0.com/docs/get-started/identity-fundamentals/authentication-and-authorization) from auth0 to learn more, but in essence:

> authentication is the process of verifying who a user is, while authorization is the process of verifying what they have access to.

There are a few gems which implement different strategies, such as [CanCanCan](https://github.com/CanCanCommunity/cancancan) and [Pundit](https://github.com/varvet/pundit).

My favourite gem for implementing authorization strategies is [ActionPolicy](https://github.com/palkan/action_policy). It's very similar to [Pundit](https://github.com/varvet/pundit), but is more extensible and isn't as barebones.

It's as simple as adding a new policy, and implementing the methods corresponding to the actions in your controller. In the example below, we have the `UnitPolicy` which will be used in the `UnitsController`. The `organization_user?` is a method which will return `true` if the user is part of the organization they're trying to access.

At the moment, most of my policies are very simple and simply check that a user is part of an organization, however, in the future it'll be easy to add permissions, roles, etc. 

```ruby
class UnitPolicy < ApplicationPolicy
  def index?
    organization_user?
  end

  def new?
    organization_user?
  end

  def create?
    organization_user?
  end

  def show?
    organization_user?
  end

  def edit?
    organization_user?
  end

  def update?
    organization_user?
  end

  def destroy?
    organization_user?
  end

  private

  relation_scope do |relation|
    relation.where(organization: organization)
  end

  params_filter do |params|
    params.permit(
      :name
    )
  end
end
```

#### Views and Components

Out of the box, Ruby on Rails uses [erb templating](https://guides.rubyonrails.org/layouts_and_rendering.html) to build views, and [partials](https://guides.rubyonrails.org/layouts_and_rendering.html#using-partials). In Rails convention over configuration fashion, it's best to have views which correspond to your `get` actions, and you'll see these views get generated when you run the scaffold generator.

However, you might want to re-use and share code between views, and at first most would reach for [partials](https://guides.rubyonrails.org/layouts_and_rendering.html#using-partials), or if you're brave enough, think that implementing a React frontend will make this better for you, but there's a better solution.

- [ViewComponent](https://viewcomponent.org/) is a framework/gem for creating reusable, testable & encapsulated view components, built to integrate seamlessly with Ruby on Rails.
- [ViewComponent::Form](https://github.com/pantographe/view_component-form) provides an ActionView FormBuilder, so you can easily use [ViewComponent](https://viewcomponent.org/) components in your form helpers

I recommend giving these two gems a try, to , and helps with the composability that one might want, 

These gems are both great at reducing the complexity and maintainability of partials, and allows for better composability, something which can be difficult in ERB templating. As mentioned previously, I've seen a lot of people reach for React frontends to solve this problem, and I think it's the wrong approach for a few reasons. If you're interested in that topic, let me know and I can publish an article going in-depth there.

#### Code formatting and linting

I highly recommend adding [standardrb](https://github.com/standardrb/standard) to your project. Under the hood it uses [rubocop](https://github.com/rubocop/rubocop) (A Ruby static code analyzer and formatter) and doesn't require any configuration - that's what makes it so powerful.

When building an MVP, you should spend the least amount of time working on things which don't directly provide value to what you're building. Linting is not a feature of your product.

When the time comes that I want to be picky about my formatting and linting rules, I'll likely pull out [standard](https://github.com/standardrb/standard) and write my own https://github.com/rubocop/rubocop rules, but in the meantime this is more than good enough.

#### Testing

Similar to linting and formatting, testing isn't really a feature. Some would highly argue against shipping code without rock-solid tests. But it really slows you down if you're hunting absolute coverage.

In my own projects, I'll use [rspec](https://rspec.info/) with [shoulda-matchers](https://github.com/thoughtbot/shoulda-matchers) alongside [FactoryBot](https://github.com/thoughtbot/factory_bot) to quickly and easily write simple tests.

For the most part, I won't add many more tests than what's included in the basic scaffold generator. Not to say I won't write tests, but covering every code path is not nescessary here. Happy path is good enough.

#### Running jobs

Ruby on Rails provides a common interface for scheduled jobs called [ActiveJob](https://guides.rubyonrails.org/active_job_basics.html), but there isn't a single job runner in the scene. There are gems such as [resque](https://github.com/resque/resque) and [sidekiq](https://github.com/sidekiq/sidekiq) but both of these gems are dependent on adding Redis.

These days, I'll be using [solid_queue](https://github.com/basecamp/solid_queue) as it's a simple solution which uses your existing SQL database.

#### Clean code

To avoid a lot of the boilerplate with [Ruby on Rails](https://rubyonrails.org/) controllers, I recommend the [responders](https://github.com/heartcombo/responders) gem. Also it's used by [devise](https://github.com/heartcombo/devise) under the hood!

## What's next?

Thanks for sticking to the end, I hope I've shared a few gems that will help you build your own [Ruby on Rails](https://rubyonrails.org/) application if you decide to do so.

As for me, I'll continue building out [HomeSuiteApartment](https://homesuiteapartment.com/), and in the next 2 weeks will mostly focus on:
- polishing pages, such as the subscription overview and unit listing page
- adding functionality to see inquiries, and book viewings from inquiries

See you in 2 weeks, for the next update!