No Scaffolds Needed

Sure We All Love Scaffolding...

It gives us all that great stuff in just one command:

  • Model
  • Controller
  • Views
  • Routes
  • Stylesheet
  • JavaScript File
  • Helper
  • Mailer

But what if we don't care about all that?

And what if we don't want a whole new set of files for each Database?

...

We only really need one of most of these (e.g., CSS & JS files).

Can't Leave It All Behind

That's not to say we won't end up with doubles.

We will need at least one controller, which is packaged with all those extras (helper, css, etc.).

But even with multiple databases, we'll be able to work with a single controller, and thus have no need bulk up on files that scaffolding each database would grant us.

Taking Stock

Let's take stock of what we will need to create:

A MODEL, which is synonymous with the Database.

ATTRIBUTES (columns) for the Database.

A CONTROLLER,

and least one VIEW.

Appropriate ROUTES for the View(s).

I'm Big Into Modelling

Assuming you're in a new project, or just any project that has no pending problems...

Let's generate a Model, which will create both the Database and your resource.rb file in the models folder.

$ rails g model Country name:string capital:string population:integer

That sure looks familiar -- just like when we Scaffold!

So, just like when we Scaffold, we need to follow up with...

$ rake db:migrate

So now all we have is a lonely Model and its Database.

But we have no way of sharing with the world what's in that DB.

Heck, we don't even have a way to enter data.

I Ran RAILS G MODEL

and All I Got Was...

Okay, there's RAILS CONSOLE. But besides that...

Sorry To Be So Controlling

Let's create a CONTROLLER, with one VIEW.

$ rails g controller Geobase sweethome

Now we've got a controller with an action,

a view, and a route!

Rails.application.routes.draw do

    get 'geobase/sweethome'

end

routes.rb

But we'll be re-visiting the Routes file in a bit.

Let's Go Viewing

On this single View page, I want to be able to:

  • Create a new Country
  • View All Existing Countries

So we'll need a form, and a loop through a collection of all countries.

geobase/sweethome.html.erb

<h1>Welcome to GEOBASE!</h1>

<div>
    <h3>Create a New Country</h3>
    <%= form_tag('/homestretch/homebase') do %>
        <strong>Name:</strong> <%= text_field_tag :country_name %><br />
        <strong>Capital:</strong> <%= text_field_tag :capital %><br />
        <strong>Population:</strong> <%= text_field_tag :population %><br />
        <%= submit_tag "Create!" %>
    <% end %>
</div>

<div>
    <h3>Listing All Countries</h3>
    <% @countries.each do |country| %>
        <p>
            <%= country.name %> • <%= country.capital %> • <%= country.population %>
        </p>
    <% end %>
</div>

Two Routes to the Same View

Notice how the Form points right back at the current page.

That makes 'geobase/sweethome' both a GET page,

and a POST page.

 

Let's update routes.rb to reflect that:

Rails.application.routes.draw do

  # might as well set the page as our root
  # and that will act as our "GET" route

  root 'homestretch#homebase'
  post 'homestretch/homebase' => 'homestretch#homebase'

end

Get It Under Control

Now we need to put some power behind that View. That means: It's Controller Time!

geobase_controller.rb

class HomestretchController < ApplicationController

    def sweethome

        # let's lay it out like we have the view page
        # first we need space to create the new Country
        # using the parameters passed through the form

        country = Country.new
        country.name = params[:country_name]
        country.capital = params[:capital]
        country.population = params[:population]
        country.save

        # then we'll collect all the Countries
        # in an instance variable

        @countries = Country.all

    end

end

Not Quite In Control

We are going to run into a problem here, though.

As we have it now, every time we come to the page, a new country will be created, whether we entered data or not.

 

Let's wrap the Country creation code is an IF statement, so it only creates a country if data has been submitted.

if params[:country_name] != nil
    country = Country.new
    country.name = params[:country_name]
    country.capital = params[:capital]
    country.population = params[:population]
    country.save
end

# a new country will only be created if
# the bare minimum of data (a name, in this
# case) is provided.

Within geobase_controller.rb, sweethome action:

Check It Out!

Twice the Models

Let's up the ante...

Why not create a second Database,

but use the same Controller and View to create new entries, and to display them?

 

So it's not just a hodgepodge of data, let's make the second resource something that's associated with the first...

$ rails g model City name:string country_id:integer

$ rake db:migrate

Association Time

Let's get those association definition done:

country.rb

city.rb

class Country < ActiveRecord::Base

	has_many :cities
	
end
class City < ActiveRecord::Base

	belongs_to :country
	
end

Add to the View

In the view, we can create a new Form by copying the old one and changing the parameters passed.

<!-- Create a New City -->
<div>
	<h3>Create a New City</h3>
	<%= form_tag('/homestretch/homebase') do %>
		<strong>Name:</strong> <%= text_field_tag :city_name %><br />
		<strong>Country:</strong> <%= select_tag :country_id, 
                 options_for_select(@countries.collect {|country| [ country.name, 
                 country.id ] }) %><br />
		<%= submit_tag "Create!" %>
	<% end %>
</div>

One note:

There are some line breaks in the that select_tag that you'll need to get ride of if you're copy-n-pasting

Add to the View, Too

To display the cities, let's pull them through the associated Countries, and display as an unordered list below each country.

<div>
	<h3>Listing Countries</h3>
	<% @countries.each do |country| %>
		<p>
			<%= country.name %> • 
                        <%= country.capital %> •
                        <%= country.population %><br />
			<ul>
				<% country.cities.each do |city| %>
					<li><%= city.name %></li>
				<% end %>
			</ul>
		</p> 
	<% end %>
</div>

More In Control

Now let's add the creation of a new city to the controller. We can just copy the country creation code, and change the variables.

Within geobase_controller.rb, sweethome action:

# the country creation code is above here

# we'll again use an IF statement to
# prevent an empty city being created
# each time we visit the page (or when
# no city data has been entered)

if params[:city_name] != nil
    city = City.new
    city.name = params[:city_name]
    city.country_id = params[:country_id]
    city.save
end

# the line collecting all Countries is below

Let's Take a Look...

A Parting Challenge...

The Capital of a Country is also a City within it, so why shouldn't it have a place in the Cities database?

 

Can you think of a way to add the Capital to the Cities database upon creation of the new Country?

No Scaffolds Needed

By argroch

No Scaffolds Needed

Creating and interacting with a database without calling the 'rails g scaffold' command.

  • 1,312