Build a Bookmark Manager with Rails

Build a full CRUD web app with Ruby on Rails using MVC architecture.

Introduction

30 Second Summary

Think about all the links you come across daily. Blog posts, documentation, tools, videos. You save them in browser tabs, sticky notes, or scattered bookmark folders, and they disappear into the void.

In this project, you will build a bookmark manager web app from scratch using Ruby on Rails. You'll go from an empty terminal to a fully interactive application running at localhost:3000 where you can save, view, edit, and delete your favourite links.

What You'll Build

You'll have a working web app where you type in a link with a title and description, hit save, and watch it appear in your personal bookmark list instantly.

By the end of this project, you'll have:

  • A live bookmark list you can pull up in your browser, click through entries, and add new links through an HTML form.
  • Full CRUD control over your saved bookmarks. You can edit titles, update URLs, or delete entries you no longer need, all from the browser.
  • Hands-on experience with the MVC pattern. You'll see how Rails routes a browser request to a controller, fetches data from the database, and renders it as HTML.
  • Secret Mission: Add validations so the app rejects bookmarks with missing titles or invalid URLs, and displays error messages in the form.

Are there any prerequisites?

You should be comfortable with at least one programming language (Python or JavaScript work great) and know how to run basic commands in a terminal. No prior Ruby or Rails experience is needed.

Before We Start

Before we dive in, let's lock in what you're about to build and why it matters to you.

Install Ruby and Rails

Before you can build a web app, you need the programming language and framework installed on your machine. Ruby is the language. Rails is the web framework that sits on top of it.

In this step, you'll install both using Mise, the version manager recommended by the official Rails installation guide.

In this step, get ready to:
  • Install system build dependencies and Mise.
  • Install Ruby 3.x via Mise.
  • Install the Rails gem.
Install system dependencies and Mise

Ruby compiles native extensions when it installs, so your system needs build tools first. After that, you'll install Mise, the version manager that handles downloading and managing Ruby versions for you.

  • Install the required system packages by running this command:
sudo apt update && sudo apt install build-essential rustc libssl-dev libyaml-dev zlib1g-dev libgmp-dev git -y

What does this command do?

This installs the compiler toolchain (build-essential), encryption libraries (libssl-dev), and other system libraries that Ruby needs to compile itself from source.

The -y flag automatically confirms the installation so you don't have to type "yes" at a prompt.

  • Install Mise by running these commands:
curl https://mise.run | sh
echo 'eval "$(~/.local/bin/mise activate)"' >> ~/.bashrc
source ~/.bashrc

What does this do?

The first line downloads and runs the Mise installer. The second line adds Mise's activation script to your shell config so it loads every time you open a terminal. The third line reloads your shell config immediately so Mise is available right now.

  • Confirm Mise is working by running:
mise --version

You should see a version number printed (something like mise 2025.x.x).

Not seeing a version number?

  • Make sure you ran source ~/.bashrc after adding the activation line. Without this, Mise isn't loaded in your current session.
  • Try running ~/.local/bin/mise --version directly. If this works but mise --version does not, re-run source ~/.bashrc or open a new terminal window.
  • help me troubleshoot Mise not being found after installation
Install Ruby via Mise

With Mise ready, you can now install Ruby. The mise use -g ruby@3 command installs the latest Ruby 3.x and makes it globally available.

  • Install Ruby by running this command:
mise use -g ruby@3

What does this command do?

The -g flag means "global", so this Ruby version is available in every terminal session. ruby@3 tells Mise to install the latest stable version of Ruby 3 (e.g. 3.3.x or 3.4.x).

This may take a few minutes as Ruby compiles from source. Once it finishes, verify the installation.

  • Check your Ruby version by running:
ruby --version

✔️ I see Ruby 3.2 or higher

You should see something like ruby 3.3.6 or ruby 3.4.1. Any version 3.2.0 or above meets the Rails 8.1 requirement.

Ruby is ready. Move on to the next substep.

ⓧ I see an older version

If you see Ruby 2.x or Ruby 3.0/3.1, your system's built-in Ruby is being used instead of the Mise-managed one.

  • Run which ruby to check the path. It should point to a Mise directory (something containing .local/share/mise).
  • If it points to /usr/bin/ruby, Mise is not activated. Run source ~/.bashrc and try ruby --version again.
  • If it still shows the wrong version, run mise doctor to check for activation issues.

ⓧ Command not found

This means Mise didn't activate properly or the Ruby install failed.

  • Run source ~/.bashrc to reload your shell configuration.
  • Run mise use -g ruby@3 again. Watch for any error messages during installation.
  • If the install fails with a compilation error, make sure all system dependencies from the previous substep installed successfully by running sudo apt install build-essential rustc libssl-dev libyaml-dev zlib1g-dev libgmp-dev -y again.
Install Rails

Ruby comes with gem, its package manager. You'll use it to install Rails.

  • Install Rails by running:
gem install rails

What is a gem?

A gem is a Ruby package. Rails itself is a gem, and it bundles dozens of smaller gems (for routing, database access, templating, and more). This command downloads Rails and all of its dependencies.

This takes a minute or two as it downloads all of Rail's dependencies. Once it finishes, it's time to verify.

  • Before you run the next command, what version number do you expect to see?
  • Check your Rails version by running:
rails --version

✔️ I see Rails 8.1.0 or higher

You should see Rails 8.1.0 or a higher patch version (like Rails 8.1.3).

Your environment is fully set up. You have Ruby and Rails ready to go.

ⓧ I see an older version

If you see Rails 7.x or Rails 8.0, you have an older version cached.

  • Update Rails by running:
gem update rails
  • Then run rails --version again to confirm you see 8.1.0 or higher.

ⓧ Command not found

This means the gem install rails command did not complete successfully, or the gem binary path isn't in your shell's PATH.

  • Run source ~/.bashrc to reload your shell.
  • Run gem install rails again and watch for errors in the output.
  • If gem itself is not found, your Ruby installation has a problem. Go back to the previous substep and re-run mise use -g ruby@3.

Your environment is ready. Next up, you'll create a brand new Rails application and see it running in your browser.

Create Your Rails App

Ruby and Rails are installed and ready to go. Now it's time to use them to create an actual web application.

In this step, you'll generate a full Rails project skeleton and prove the framework is working by launching a development server and seeing the Rails welcome page in your browser.

In this step, get ready to:
  • Generate a new Rails application called bookmarks.
  • Boot the development server and see the Rails welcome page.
  • Explore the project structure in VS Code.
Generate the application and boot the server

Rails has a built-in generator that scaffolds an entire web application for you. One command creates dozens of files organized into a convention-based folder structure.

  • In your terminal, move to your Desktop by running this command:
cd ~/Desktop
  • Generate a new Rails application called bookmarks by running:
rails new bookmarks

What does this command do?

This creates a bookmarks/ folder on your Desktop containing the full Rails application skeleton.

It also runs bundle install automatically, which downloads all the Ruby libraries (gems) your app needs. This takes a minute or two depending on your internet speed.

You'll see a long list of files being created, followed by a bundle install log. Wait until it finishes and your terminal prompt returns.

Seeing network errors during bundle install?

If bundle install fails with a connection error, check your internet connection and retry by running cd ~/Desktop/bookmarks && bundle install.

help me fix bundle install errors

  • Move into the new project folder and create the database by running these commands:
cd bookmarks
bin/rails db:create

What does db:create do?

Rails uses SQLite as its default database. The db:create command creates the database files your app needs to store data.

You should see output confirming that your databases were created.

  • Start the development server by running:
bin/rails server

What does this command do?

This starts Puma, the web server built into Rails, on port 3000. It takes over your terminal while it runs. You'll see log output every time a request hits your app.

Before you open the browser, what do you expect to see at http://localhost:3000?

  • Open your browser and navigate to http://localhost:3000.

You should see the Rails welcome page with the Rails logo and version information. This confirms your application is running.

Don't see the welcome page?

Make sure the server is still running in your terminal. If you see an error, check that you ran bin/rails server from inside the bookmarks directory.

Also confirm you're visiting http://localhost:3000 (not https).

help me get the Rails server running

Explore the project structure

Your Rails app is made up of dozens of files organized into a specific folder structure. Understanding the key directories helps you know where to put things.

  • Open a new terminal tab by pressing Ctrl+Shift+T (or open a new terminal window).
  • Navigate to your project and open it in VS Code by running:
cd ~/Desktop/bookmarks
code .

VS Code opens with the full project loaded in the sidebar.

  • In the Explorer sidebar on the left, look at the top-level folders.

What are the key directories?

Three folders matter most right now:

  • app/ contains your models, views, and controllers. This is where you'll spend most of your time building features.
  • config/routes.rb is the routing file. It maps incoming URLs to the right controller action.
  • db/ holds your database schema and migration files. Migrations are how Rails tracks changes to your database structure over time.

What is MVC?

Rails uses the MVC pattern to organize code. Models handle data and business logic. Views render HTML for the browser. Controllers sit in between, receiving requests and deciding which model to query and which view to render.

  • Expand the app/ folder in the sidebar.
  • Notice the models/, views/, and controllers/ subfolders inside it.

Every feature you build will touch all three of these folders.

Stop the server
  • Switch back to the terminal where the Rails server is running.
  • Press Ctrl+C to stop the server.

Your terminal prompt returns and the server is no longer running. You'll start it again in later steps when you need to check your work in the browser.

Your Rails app is scaffolded and proven working. Next up, you'll create a database table to store bookmarks and learn how to interact with your data using the Rails console.

Build the Data Layer

Your Rails app is running and the welcome page confirms the framework is working. Now it's time to give it something to work with: actual bookmark data stored in a database.

Before you can display bookmarks in a browser, you need a database table to hold them. In this step, you'll use Active Record (the Rails ORM) to create that table, then add records through the Rails console.

In this step, get ready to:
  • Generate the Bookmark model and database migration.
  • Create bookmark records using the Rails console.
  • Confirm the data exists but has no web interface yet.
Generate the Bookmark model

Rails has a generator that creates a model file and a database migration in one command. The migration is a Ruby file that tells the database what table and columns to create.

  • Generate the Bookmark model with its columns by running these commands:
bin/rails generate model Bookmark title:string url:string description:text
bin/rails db:migrate

What do these commands do?

  • bin/rails generate model creates two files: app/models/bookmark.rb (the model class) and a timestamped migration file in db/migrate/.
  • bin/rails db:migrate runs that migration, creating a bookmarks table with columns for title, url, description, created_at, and updated_at.
  • You should see terminal output confirming the migration ran, including a line like create_table(:bookmarks).

Seeing an error about the database?

If you see an error mentioning the database not existing, run bin/rails db:create first, then retry bin/rails db:migrate.

Make sure your terminal is inside the bookmarks folder (not the parent directory).

help me fix a Rails migration error

Add bookmarks via the Rails console

The Rails console lets you interact with your database using Ruby code directly. You'll use it to create a couple of bookmark records so you have real data to work with.

  • Open the Rails console by running:
bin/rails console
  • Create two bookmarks and verify they were saved by entering these commands one at a time:
Bookmark.create(title: "Ruby Docs", url: "https://ruby-lang.org", description: "Official Ruby site")
Bookmark.create(title: "Rails Guides", url: "https://guides.rubyonrails.org", description: "Learn Rails")
Bookmark.all

What does this code do?

  • Bookmark.create(...) instantiates a new Bookmark object, fills in the fields, and saves it to the database in one step.
  • Bookmark.all retrieves every record in the bookmarks table and returns them as Ruby objects.
  • You should see your two bookmarks returned as Ruby objects with their id, title, url, and description fields filled in.
  • Exit the console by typing:
exit

Seeing NameError or uninitialized constant?

If the console says it doesn't recognize Bookmark, the migration may not have run successfully. Exit the console with exit, run bin/rails db:migrate, then open the console again.

help me fix NameError in the Rails console

Try visiting the bookmarks in the browser

Your bookmark data now lives in the database. Let's see what happens when you try to view it in a browser.

  • Start the Rails server by running:
bin/rails server

Before you open the URL, take a guess: what do you think will happen when you visit http://localhost:3000/bookmarks?

  • Open http://localhost:3000/bookmarks in your browser.

You see a routing error page: No route matches [GET] "/bookmarks".

Why does this happen?

The data exists in the database, but Rails has no idea how to show it in a browser. A model only handles data storage.

To display records on a web page, you need three more pieces: a route that maps the URL to a controller, a controller that fetches the data, and a view that renders the HTML. That's the MVC pattern in action.

Your data layer is solid. Next up, you'll connect routes, a controller, and views so those bookmarks actually show up in the browser.

Display Bookmarks in the Browser

You have bookmarks sitting in your database, but the only way to see them is through the Rails console. That is like having a library with no front door.

This step connects the dots between your database and the browser using the MVC pattern: routes tell Rails where to send requests, controllers fetch the data, and views render the HTML. By the end, you will see your bookmarks as clickable links in a real web page.

In this step, get ready to:
  • Define routes that map browser URLs to controller actions.
  • Build a controller and views that display bookmarks from the database.
  • Verify the full MVC loop from browser to database and back.
Define routes

Routes are the map that tells Rails which code to run when a browser hits a specific URL. Without routes, Rails has no idea what to do with /bookmarks.

  • Switch back to the terminal where your Rails server is running.
  • Stop the server by pressing Ctrl+C.
  • Open config/routes.rb in VS Code and replace its entire contents with:
Rails.application.routes.draw do
  root "bookmarks#index"
  resources :bookmarks
end

What does this code do?

  • root "bookmarks#index" sets the homepage of your app to the bookmarks list.
  • resources :bookmarks generates all seven RESTful routes (index, show, new, create, edit, update, destroy) in one line.
  • Save config/routes.rb.
  • Confirm the routes exist by running this command:
bin/rails routes

You should see a table with columns for Prefix, Verb, URI Pattern, and Controller#Action. Look for bookmarks#index and bookmarks#show in the output.

Don't see any routes?

  • Make sure you saved config/routes.rb before running the command.
  • Check that you are inside the bookmarks folder when running the command.
  • help me debug my Rails routes
Generate the controller and build the index view

Routes point to a controller, but that controller does not exist yet. Rails provides a generator that creates the controller file and its matching view folder in one command.

  • Generate the Bookmarks controller by running:
bin/rails generate controller Bookmarks index --skip-routes

You should see output listing several created files, including app/controllers/bookmarks_controller.rb and app/views/bookmarks/index.html.erb.

What does --skip-routes do?

The generator normally adds a route for you, but you already defined your own routes in the previous substep. The --skip-routes flag prevents the generator from overwriting your work.

  • Open app/controllers/bookmarks_controller.rb in VS Code and replace its entire contents with:
class BookmarksController < ApplicationController
  def index
    @bookmarks = Bookmark.all
  end

  def show
    @bookmark = Bookmark.find(params[:id])
  end
end

What does this code do?

  • The index action loads every bookmark from the database into @bookmarks. The @ makes it available to the view template.
  • The show action finds one specific bookmark by its ID from the URL and stores it in @bookmark.
  • Save app/controllers/bookmarks_controller.rb.
  • Open app/views/bookmarks/index.html.erb and replace its entire contents with:
<h1>My Bookmarks</h1>

<div id="bookmarks">
  <% @bookmarks.each do |bookmark| %>
    <div>
      <%= link_to bookmark.title, bookmark_path(bookmark) %>
    </div>
  <% end %>
</div>

What does this template do?

  • ERB tags <% %> run Ruby code without printing. Tags with <%= %> run Ruby code AND print the result into the HTML.
  • @bookmarks.each loops through every bookmark the controller loaded from the database.
  • link_to generates an HTML anchor tag. It takes the link text (the bookmark title) and the path (bookmark_path(bookmark) produces /bookmarks/1).
  • Save app/views/bookmarks/index.html.erb.
  • Start the Rails server by running:
bin/rails server
  • Open http://localhost:3000/bookmarks in your browser.

You should see a heading that says "My Bookmarks" with "Ruby Docs" and "Rails Guides" listed as clickable links. The routing error from earlier is gone.

Still seeing an error page?

  • If you see "uninitialized constant BookmarksController", make sure the controller file is saved and that the class name is exactly BookmarksController (capital B, plural).
  • If you see a template-missing error, confirm that app/views/bookmarks/index.html.erb exists and is saved.
  • help me fix my Rails controller or view error
  • Now create the show view. In VS Code, create a new file at app/views/bookmarks/show.html.erb and paste in:
<h1><%= @bookmark.title %></h1>
<p><%= link_to @bookmark.url, @bookmark.url, target: "_blank" %></p>
<p><%= @bookmark.description %></p>

<%= link_to "Back", bookmarks_path %>

What does this template do?

  • It displays the single bookmark that the show action loaded into @bookmark.
  • The URL is rendered as a clickable external link (target: "_blank" opens it in a new tab).
  • The "Back" link uses bookmarks_path to return to the index page.
  • Save app/views/bookmarks/show.html.erb.

✔️ Awesome, I've got everything!

Great. Double check you have saved all four files: config/routes.rb, bookmarks_controller.rb, index.html.erb, and show.html.erb.

ⓧ I'd like to double check the full code

Here is the full code for each file you created or edited in this step.

Rails.application.routes.draw do
  root "bookmarks#index"
  resources :bookmarks
end
class BookmarksController < ApplicationController
  def index
    @bookmarks = Bookmark.all
  end

  def show
    @bookmark = Bookmark.find(params[:id])
  end
end
<h1>My Bookmarks</h1>

<div id="bookmarks">
  <% @bookmarks.each do |bookmark| %>
    <div>
      <%= link_to bookmark.title, bookmark_path(bookmark) %>
    </div>
  <% end %>
</div>
<h1><%= @bookmark.title %></h1>
<p><%= link_to @bookmark.url, @bookmark.url, target: "_blank" %></p>
<p><%= @bookmark.description %></p>

<%= link_to "Back", bookmarks_path %>
Verify in the browser

Before you click, think about what should happen. When you click "Ruby Docs" on the index page, which controller action runs, and what do you expect to see?

  • In your browser at http://localhost:3000/bookmarks, click the "Ruby Docs" link.

You should see a detail page with the title "Ruby Docs", the URL https://ruby-lang.org as a clickable link, the description "Official Ruby site", and a "Back" link that returns you to the list.

What just happened?

The browser sent a GET request to /bookmarks/1. Rails matched that to the show route, called BookmarksController#show, which loaded the bookmark from the database and rendered show.html.erb.

This is the full MVC loop: the route dispatches the request, the controller queries the model, and the view presents the result.

Clicking a link gives a template error?

  • Make sure app/views/bookmarks/show.html.erb exists and is saved. The filename must be exactly show.html.erb (not Show.html.erb or show.erb).
  • Confirm the file is inside app/views/bookmarks/ and not in a different folder.
  • help me fix my missing template error in Rails

The MVC loop is working, but you can only view bookmarks. To add new ones, you still need the Rails console. Next up, you will add HTML forms so you can create, edit, and delete bookmarks directly from the browser.

Add Forms for Full CRUD

Your bookmarks are visible in the browser, but adding new ones still requires the Rails console. That defeats the purpose of a web app.

A real application lets users create, edit, and delete records directly from HTML forms. In this step, you will build those forms using Rails form helpers and complete the full CRUD cycle so the app is fully interactive.

In this step, get ready to:
  • Build an HTML form partial and a "New bookmark" page that submits to the database.
  • Add edit, update, and delete functionality so every bookmark is modifiable from the browser.
  • Wire all actions together with strong parameters and a before_action callback.
Create the form partial and new bookmark page

You need a controller that knows how to handle form submissions before any view will work. The controller also needs private helper methods to keep your code DRY.

  • Open app/controllers/bookmarks_controller.rb in VS Code.
  • Replace the entire file contents with the following public actions:
class BookmarksController < ApplicationController
  before_action :set_bookmark, only: %i[show edit update destroy]

  def index
    @bookmarks = Bookmark.all
  end

  def show
  end

  def new
    @bookmark = Bookmark.new
  end

  def create
    @bookmark = Bookmark.new(bookmark_params)
    if @bookmark.save
      redirect_to @bookmark
    else
      render :new, status: :unprocessable_entity
    end
  end

What does this code do?

  • before_action :set_bookmark automatically finds the bookmark by ID before show, edit, update, and destroy run. This replaces the manual Bookmark.find you had before.
  • show is now empty because set_bookmark already loads @bookmark for it.
  • new creates a blank Bookmark object for the form to bind to.
  • create attempts to save the form data. On success it redirects to the show page. On failure it re-renders the form.
  • Directly below the create method's end, add these private helper methods and close the class:

  private
    def set_bookmark
      @bookmark = Bookmark.find(params[:id])
    end

    def bookmark_params
      params.expect(bookmark: [:title, :url, :description])
    end
end

What are strong parameters?

params.expect(bookmark: [:title, :url, :description]) is a security feature called strong parameters. It ensures only the fields you explicitly allow (title, url, description) can be submitted through the form. Anything else gets rejected.

  • Save app/controllers/bookmarks_controller.rb.
  • In your browser, visit http://localhost:3000/bookmarks/new.

You should see an error page mentioning a missing template. This confirms the route and controller action are working. Rails just does not have a view to render yet.

Seeing a different error?

  • If you see a syntax error, check that you have the end keyword closing the class on the very last line of the file.
  • Make sure private appears between the last action's end and the final end that closes the class.
  • Help me fix a syntax error in my Rails controller.

Now you will create the form that Rails needs to render. Partials are reusable view fragments in Rails. A partial filename starts with an underscore.

  • Create a new file called _form.html.erb inside app/views/bookmarks/ and add the following code:
<%= form_with model: bookmark do |form| %>
  <div>
    <%= form.label :title %>
    <%= form.text_field :title %>
  </div>

  <div>
    <%= form.label :url %>
    <%= form.url_field :url %>
  </div>

  <div>
    <%= form.label :description %>
    <%= form.textarea :description %>
  </div>

  <div>
    <%= form.submit %>
  </div>
<% end %>

What does this form do?

  • form_with model: bookmark generates an HTML form that automatically posts to the correct URL based on whether the bookmark is new or existing.
  • form.text_field :title creates a text input. form.url_field :url creates a URL-type input with browser validation. form.textarea :description creates a multi-line text area.
  • form.submit generates a submit button with text that automatically reads "Create Bookmark" or "Update Bookmark" depending on context.
  • Create another new file called new.html.erb in the same app/views/bookmarks/ folder with this code:
<h1>New bookmark</h1>

<%= render "form", bookmark: @bookmark %>
<%= link_to "Cancel", bookmarks_path %>

What does render do here?

render "form", bookmark: @bookmark inserts the _form.html.erb partial into this page and passes @bookmark as a local variable called bookmark. This lets you reuse the same form for both creating and editing.

  • Save both files.
  • Refresh http://localhost:3000/bookmarks/new in your browser.

You should see a heading that says "New bookmark", three labelled form fields (Title, Url, Description), a "Create Bookmark" button, and a Cancel link.

Still seeing the missing template error?

  • Make sure the file is named exactly new.html.erb (not new.erb or new.html) and lives inside app/views/bookmarks/.
  • Check that the partial is named _form.html.erb with the leading underscore.
  • Help me debug why my new bookmark page still shows a missing template error.

The form renders, but there is no way to reach it from the bookmarks list. You need a link on the index page.

  • Open app/views/bookmarks/index.html.erb.
  • Find this line:
<h1>My Bookmarks</h1>
  • Add the following line directly below it, so there is a blank line between the heading and the link:
<h1>My Bookmarks</h1>

<%= link_to "New bookmark", new_bookmark_path %>
  • Save index.html.erb.
  • Visit http://localhost:3000/bookmarks in your browser.

You should see a "New bookmark" link at the top of the page. Click it, fill in a title, URL, and description, then click Create Bookmark. The new bookmark appears on its show page.

Add edit, update, and destroy actions

Creating bookmarks works. Now you will add the ability to edit and delete them so the app has the complete CRUD cycle.

  • Return to app/controllers/bookmarks_controller.rb.
  • Find the blank line between the create method's end and the private keyword.
  • Add these three actions in that space:
  def edit
  end

  def update
    if @bookmark.update(bookmark_params)
      redirect_to @bookmark
    else
      render :edit, status: :unprocessable_entity
    end
  end

  def destroy
    @bookmark.destroy
    redirect_to bookmarks_path
  end

What do these actions do?

  • edit is empty because set_bookmark already loads the record. It just renders the edit form.
  • update applies the form data to the existing record. If validation passes it redirects. Otherwise it re-renders the edit form.
  • destroy deletes the record and sends the user back to the bookmarks list.
  • Create a new file called edit.html.erb inside app/views/bookmarks/ with this code:
<h1>Edit bookmark</h1>

<%= render "form", bookmark: @bookmark %>
<%= link_to "Cancel", @bookmark %>

Why does Cancel link to @bookmark here?

link_to "Cancel", @bookmark generates a link to the bookmark's show page. Rails automatically converts an Active Record object into its URL path. On the new page, Cancel goes to the bookmarks list instead because the record does not exist yet.

  • Save the controller and the new edit.html.erb file.
  • In your browser, visit http://localhost:3000/bookmarks/1/edit.

You should see the edit form pre-filled with your first bookmark's data. The submit button reads "Update Bookmark" automatically.

Seeing a missing template error for edit?

  • Check that edit.html.erb is in app/views/bookmarks/ (not in a subfolder).
  • Make sure the file is named edit.html.erb with no typos.
  • Help me fix a missing template error on my edit bookmark page.

The last piece is adding Edit and Delete controls to the show page so users can reach these actions.

  • Open app/views/bookmarks/show.html.erb.
  • Find this line at the bottom:
<%= link_to "Back", bookmarks_path %>
  • Add the following two lines directly below it:
<%= link_to "Edit", edit_bookmark_path(@bookmark) %>
<%= button_to "Delete", @bookmark, method: :delete, data: { turbo_confirm: "Are you sure?" } %>

What does button_to do?

button_to creates a mini HTML form that submits a DELETE request when clicked. The turbo_confirm option shows a browser confirmation dialog before deleting. This prevents accidental deletions.

  • Save show.html.erb.
  • Visit http://localhost:3000/bookmarks/1 in your browser.

You should see Back, Edit, and Delete controls on the bookmark's show page.

✔️ Awesome, I've got everything!

Great. Double check you have saved all your files.

ⓧ I'd like to double check the full code

Your controller was built across multiple chunks. Scroll up and confirm each piece is present in this order:

  • The class opens with before_action :set_bookmark.
  • Public actions: index, show, new, create, edit, update, destroy.
  • private section with set_bookmark and bookmark_params.
  • A single end closing the class on the final line.

For the view files, confirm:

  • _form.html.erb has form_with model: bookmark with title, url, and description fields.
  • new.html.erb renders the form partial and has a Cancel link to bookmarks_path.
  • edit.html.erb renders the form partial and has a Cancel link to @bookmark.
  • index.html.erb has link_to "New bookmark", new_bookmark_path between the heading and the bookmarks div.
  • show.html.erb has Back, Edit, and Delete controls at the bottom.
Test the full CRUD cycle

Every piece is in place. Before you test, think about what you expect to happen when you create, edit, and delete a bookmark.

  • Visit http://localhost:3000 in your browser.
  • Click New bookmark.
  • Enter GitHub for the title, https://github.com for the URL, and Code hosting platform for the description.
  • Click Create Bookmark.

You land on the new bookmark's show page with the title "GitHub" and the URL linked.

  • Click Edit.
  • Change the description to Where the world builds software.
  • Click Update Bookmark.

You land back on the show page with the updated description.

  • Click Delete.
  • Confirm the deletion in the browser dialog.

You are redirected to the bookmarks list. The deleted bookmark is gone. Full CRUD is working from the browser.

Delete button not working?

  • Make sure you used button_to (not link_to) for the delete control. A regular link sends a GET request, but delete needs a DELETE method.
  • Check that method: :delete is inside the button_to call, not a separate attribute.
  • Help me debug why my delete button is not removing bookmarks.

Your bookmark manager is fully interactive. You can create, read, update, and delete bookmarks entirely from the browser. Next up, you will push this further by adding validations that protect your data.

Secret mission

Add Validations and Error Messages

Right now your app happily saves bookmarks with no title or a completely invalid URL. Real applications validate user input before saving it to the database. In this secret mission, you'll add Active Record validations to your Bookmark model and display helpful error messages when the form submission fails.

Clean Up Your Resources

Clean Up Your Resources

This project runs entirely locally on your machine. There are no cloud resources or ongoing costs to worry about.

Decide whether to keep your resources running, pause them to come back later, or delete them entirely.

Resources you used:

  • The bookmarks Rails project folder on your Desktop.
  • Ruby 3.x installed via Mise.
  • The Rails gem installed globally.
  • Mise version manager installed at ~/.local/bin/mise.

Keep everything running

No action needed. Choose this if you plan to keep building on this Rails app or want to start another Rails project soon.

  • Ruby, Rails, and Mise stay installed and ready for your next project.
  • Your bookmarks folder stays on your Desktop.
  • If the Rails server is still running, stop it with Ctrl+C when you are done for the day.

Pause - I'll come back to this later

Shut down running processes to free up memory. Your files and tools stay installed for when you return.

  • Stop the Rails server by pressing Ctrl+C in the terminal where it is running.
  • Close VS Code if you are done for now.
  • When you come back, open the bookmarks folder in VS Code and run bin/rails server to pick up where you left off.

Delete - I don't want to use this again

Remove all project resources and tools to start fresh.

  • Stop the Rails server by pressing Ctrl+C if it is still running.
  • Delete the project folder by running:
rm -rf ~/Desktop/bookmarks
  • Uninstall the Rails gem by running:
gem uninstall rails
  • Remove Ruby (installed via Mise) by running:
mise uninstall ruby
  • Remove Mise itself and all of its data by running:
mise implode
  • Remove the Mise activation line from your shell config by running:
sed -i '/mise activate/d' ~/.bashrc
  • Reload your shell to apply the change:
source ~/.bashrc

Nice Work!

Nice Work!

You just built a fully interactive bookmark manager from scratch using Ruby on Rails. Starting from a blank terminal, you installed Ruby, generated a Rails app, and ended up with a working CRUD application running at localhost:3000.

You've learned how to:

  • Build a complete CRUD web application where users can create, view, edit, and delete bookmarks entirely from the browser.
  • Connect the MVC pattern end-to-end: routes dispatch requests to controller actions, controllers query Active Record models, and ERB views render the HTML response.
  • Use Rails conventions like resourceful routing, strong parameters, form helpers, and partials to keep your code DRY and organised.
  • Secret Mission: Added model validations with custom error messages that display in the UI when users submit invalid data.

Ready to quiz yourself?