DEV Community

Cover image for Adding Models to an already large Codebase without using scaffold.
Robert Hustead
Robert Hustead

Posted on

Adding Models to an already large Codebase without using scaffold.

tl;dr
Follow this Order:

  1. Create an ERD
  2. Create a Migration
  3. Create the Model
  4. Manage Permissions to the Model
  5. Specify the Routes
  6. Create the Controller
  7. Create the Views

If you're just joining a team of developers for the first time, it can be daunting trying to figure out where to start when adding functionality or new models. There are hundreds of files of code and so many moving parts that you may or may not have any idea what they do. While there is a lot of talk about TDD (Test Driven Development) and writing specs before writing any bit of code, I've found it helpful to create a basic prototype or skeleton of what I'd like before getting too deep into tests. And the good thing is, adding models to an already large codebase is easy!

There are many ways to develop, but I've found following a series of logical steps helps me. So here is my general thought process and steps toward adding functionality to an already large codebase. I won't go into major details for syntax(like how exactly to set up a migration), as you can google that information easily and I'm assuming the reader has a base knowledge of Rails. Moreover, every codebase and team is different. Instead, I'm focusing creating an overall guide to influence your decision process when you stand back and go 'what next?' This post is aimed towards beginner developers who understand the basics about Rails but may not have enough experience yet to feel fully comfortable and to get to them to the point where they don't have to worry about setting things up and to get right into the 'real coding'.

It should be noted that much of this work can be done using Rails generate scaffold command from the command line. However, if you're not 100% sure what exactly Rails will create and do, or if you're not yet comfortable creating basic scaffolding on your own, I suggest following these steps.

1. Create an ERD (Entity Relationship Diagram)

Before you write any code at all, you need to plan out what exactly you're going to be creating. You should take some time to figure out what type of model you will need, what attributes it will have, and how it will be related to other models within your codebase.
Example ERD:
Imgur Built at www.draw.io
Creating a solid ERD is argueably the most important step in the creation process, so take your time! As the old adage goes, "Measure twice, cut once."

2. Create a Migration!

The first step for creating a new model is to prepare the database to store it's information. If you're coming into a code base and have already gotten it working locally, then the databases (usually defined in your config/database.yml file) have likely already been created. So, you'll only need to create a migration.

General syntax for Migration: $ rails generate migration name_here

This will create a migration file for you, using the name you used in name_here and adding a timestamp to it. Open that file, and create the table you need with the fields you need. Note that the name of the table will be plural. For example, if you wanted to create an Article model, the name of the table in the database will be articles.
See: Active Record Migrations — Ruby on Rails Guides

When your migration file is finished, run: $: rails db:migrate
If for some reason you notice a mistake, or want to undo the changes, you can rollback with: $: rails db:rollback

After the migration runs successfully, you now have a table in your database to store the data for your new model!

3. Create the Model

Next, we will need to write the Rails code for the actual model. Depending on your project, you may have various domains for models, but you can often find all the models you'll need in the app/models directory. Some things to note: the filename should begin with a lowercase letter and be singular. The name of the class within the file should be uppercase and singular as well. So, create a new file in your models directory with the name of your model.

Let's look at an example. Let's say you just created a new table articles through a migration.
In your app/models/article.rb file(notice lowercase and singular)

class Article < ApplicationRecord

end
Enter fullscreen mode Exit fullscreen mode

That's it! You now have a model. Jump into the rails console ($ rails c) to check that it's working as expected. Don't worry about validations or relationships just yet. Let's get everything working correctly first, then we can worry about wiring it all up.

4. Manage Permissions to use the Model

Who will be able to use your Model? By that I mean, will every user to your site be able to read information the model contains? Will they be able to create new ones? Or will you reserve the right to create new models only to admins? If you're coming into a large codebase, likely there will already be some sort of User Authentication service (like Devise(GitHub - plataformatec/devise: Flexible authentication solution for Rails with Warden.)) and Resource Permission Management Service(like CanCan(GitHub - plataformatec/devise: Flexible authentication solution for Rails with Warden.))

Whatever library you use, you should look into how to add (or restrict) permissions to your Model. In the case of CanCan, you will have an ability file in your app/models directory. Within that ability file, you can add permissions based on the type of user.

For example, your ability file may look something like this:

class UserAbility
  include CanCan::Ability

  def initialize(user)
    can :read, Instruction
    can :manage, Gadget if user.admin?
    can [:show, :map], Restaurant
  end
end
Enter fullscreen mode Exit fullscreen mode

It's not imperative to understand everything that's going on here, but you should look into how whatever library you use works when you can. In CanCan's case, within an initialize method you specify what actions(in the Controller) a user can perform on a Model. :read is shorthand for :show, :index, while :manage allows for all normal CRUD actions. If you have other actions you will need to perform, you can add them as well by using an array of symbols.

If you're not sure, for the time being you can just add your model and allow the user to :manage and change it later, but you should think about who exactly will be using the model and what they will be doing with it.

This step is must be completed now because if you do not give permission to access the Model, you won't be able to test your controllers or views later. Each request to use the resource will be stopped by the Application controller and you'll get an error.

5. Create your Routes

After you've given permission to access the model, you'll need to define the route a user will take to reach that resource. It's easy to forget setting up routes, so I find doing this before creating controllers and views to be a logical next step in the process.

Within your config/routes.rb file, you'll need to specify the routes that will access your controller(which we will make next). If your application uses many namespaces, you should take care that you specify routes within the correct namespace or nested within the proper related resource. Also, you'll need to specify any actions that fall outside the realm of the normal CRUD actions. If you nested the routes within another resource, take note of it, as you'll need that information for the next step.

6. Create the Controller

Finally we can create the Controller for our Model. You may already be worried about all the functionality or data parsing or logic you know you'll need to add, but don't worry about all that yet! All we should worry about right now is making sure that when we put in a URL, our application reacts as expected and routes our request to our Controller.

First, we must create the Controller file, and this can be a little tricky. If your Controller is not nested within a namespace or other resource, you can just create a new file in your app/controllers directory. However if your Controller IS nested within another resource, you'll need to either create directory for your new Controller, or be sure to create your Controller within the proper directory if it already exists.

In the proper directory, create a new file to serve as the controller. This file will need to follow the basic naming structure of the plural of your model + underscore + controller. For example, articles_controller.rb

In your Controller, define all the actions the Controller will have. You don't need to add any logic to them; just define them. This example is for a non nested resource. Note the Model name is in uppercase, plural, and there is no underscore:

class ArticlesController < ApplicationController
  def show; end
end  
Enter fullscreen mode Exit fullscreen mode

If your controller is nested, you'll have something like this:

class AdminDomain::ArticlesController < AdminDomain::ApplicationController
  def show; end
end
Enter fullscreen mode Exit fullscreen mode

A couple things to note: Remember that the AdminDomain::ArticlesController is NOT inhereiting from something called AdminDomain. The :: is a scope resolution operator, and is serving to tell the compiler that this ArticlesController is located within the AdminDomain, not that it inherits anything. The inheritance is shown after the <, which states the AdminDomain::ArticlesController inherits from AdminDomain::ApplicationController, but you could just as easily have it inhereit from WriterDomain::ApplicationController or ApplicationController (thought this would likely lead to unexpected behavior.) Also, it's technically unnecessary to define blank methods as Rails is kind enough to do default actions without an explicit method declaration. But for clarity sake (and for you to double check what methods you'll have), I suggest declaring them.

7. Create the Views

The default behavior for an action in a controller is to render the view that shares the same name. So, with our blank actions declared in the controller, we should go about making our Views. Like with the controller, you will need to remember if your resource is nested or not. If not, you can simply create a folder in your app/views directory that is the plural of your model name. For example, you would create a app/views/articles directory for all Article views assuming the ArticleController is not nested inside another resource.

Inside your new directory, create a blank file for your view, and give it the file name that reflects the action in the controller. Rails uses ERB out of the box, but check what templating language your team uses and create a file that ends with that extension.
For ERB, app/views/articles/show.html.erb
For HAML, app/views/articles/show.html.haml
etc.

For now, just add a single line in the file to make sure it's working properly. Something like,

<h1>Hello World!</h1>
Enter fullscreen mode Exit fullscreen mode

Now you should be able to put in the URL for the show action of the Topics Controller (check your routes if you're not sure how to access it), and recieve a large "Hello World!" response.

Start Coding!

You're all done! That is to say, you've just started. But you've done all the basic work required to add a Model, Controller, Routes, and Permissions to the codebase. Now you can start worrying about more practical matters, like how you want the page to look, or what data you want to query from the database, or what data you want the Model to validate, the tests you'll need to create, or any of the other concerns that come with creating new functionality.

Good luck and happy coding!

Top comments (2)

Collapse
 
didin1453fatih profile image
Didin 👨‍💻

Nice post!!!
draw.io just create design visual, I think You can try dbdesigner.id to create Entity Relationship Diagram 😎😎😎.
This can help you to collaborate with your team on web and cut off your step in generate SQL Create database.
I write this article to explain more about this devtool dev.to/didin1453fatih/database-des...

Alt Text

Collapse
 
husteadrobert profile image
Robert Hustead

Thanks for the question! There is no real reason beyond inviting the coder to do all the work themselves so they cement the knowledge of how these things are set up. That's all!