Throughout decades of client-server computing, the architecture of database-driven applications has been designed by database administrators working in the "enterprise". This architecture places the responsibility for managing data squarely in the database itself. Applications are considered "dumb", not to be trusted with vital tasks like data validation and formatting, or managing relationships between different tables. Using this traditional architecture, we might manage our Intranet application's data structures (see Chapter 2) like this:
id
field of a record in the companies
table changed, any references to that in the people
table would be updated. companies
table, ordered by company name.By contrast, in the Rails view of the world, the application is king, and the database is its servant. This is due to Rails being the product of web developers: in the web development environment, databases are typically unsophisticated buckets for holding "stuff" (because they are often designed by people who aren't full-time database administrators).
However, beyond this, performing database operations through model classes simplifies database access considerably: making a change to an application can be done in the high-level application code, rather than by modifying low-level SQL code in the database layer. Therefore, operations, which would be delegated to the database in the traditional client-server architecture (such as the ones in the bullet points above) are instead handled by ActiveRecord in a Rails application.
ActiveRecord is a so-called object-relational mapping (ORM) layer (also known as a relational persistence layer), similar in scope to Hibernate (Java) or ADODB (PHP). Instead of dealing with the database through SQL statements, an ORM layer presents records in a database table as a series of objects; it also provides class-level methods for creating database connections, querying tables, and so on. The fields in a record are not read or written directly, but accessed through instance methods on an object. This reduces the complexity and tedium of working with a relational database, as the onus for creating database connections, correctly formatting SQL statements, escaping quote marks in strings, etc. is moved into the ORM layer, away from the developer.
Bruce Tate and Curt Hibbs call ActiveRecord an Object Relational Wrapping layer, rather than a Mapping layer: their view is that as there is no explicit configuration of the relationship between the model classes and the database tables, it doesn't count as a "mapping". They have a point, but the exact semantics aren't too important. Here, I'm treating "mapping" in the sense that objects can be mapped onto records in the database tables.
An ORM layer is one way to implement the model part of the MVC architecture, and this is the role ActiveRecord fulfils in a Rails application: it acts as the intermediary between the controller and the database, retrieving, validating, updating, and deleting records on behalf of the controller.
Before we can see how this works, we need a database to use as the back-end for our application. Setting this up is covered in the following sections.
As described in Chapter 2, we're going to use MySQL as the database back-end for the Intranet application. If you followed the installation instructions, you should have MySQL available on your machine.
The first step is to initialise the MySQL database. You could use one of the MySQL GUI clients to do this, but we'll use the command line as this works the same regardless of your platform. Use this command to login to the database server on your local machine:
$ mysql -u root -p
Note that -u root
specifies we are logging in as the root user: you need to use an account with sufficient privileges to create a new database. -p
indicates that we intend to use a password to login. If your login is successful, you should see:
Welcome to the MySQL monitor. Commands end with ; or g.
Your MySQL connection id is 1 to server version: 5.0.24a
Type 'help;' or 'h' for help. Type 'c' to clear the buffer.
mysql>
Once you've logged in successfully, create a database called intranet_development with:
mysql> CREATE DATABASE intranet_development;
Query OK, 1 row affected (0.05 sec)
This is the database we'll be using during the development of our application. The next step is to create a user account for our Rails application. This is a good practice: instead of using a real person's account (or even worse, the root account) to connect our Rails application to MySQL, we will use a dedicated system account. This gives us a handful of security advantages:
CREATE TEMPORARY TABLES
permission, for example. MySQL allows us to refine permissions further, down to the individual table and row level if required.Again, you can use either a GUI tool or the command line to create the system account. Here's how to do it on the command line (once you are logged in to MySQL):
mysql> GRANT ALL ON intranet_development.* TO intranet@localhost IDENTIFIED BY 'police73';
Query OK, 0 rows affected (0.01 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 0 rows affected (0.00 sec)
This simultaneously creates the intranet user account and gives that user all permissions (known as privileges in MySQL) on the intranet database. The IDENTIFIED BY
clause specifies the account password ('police73'). @localhost
specifies the host name from which this user can access the database. If the database server is on a separate physical box from the application server, the application server's IP address or domain name should be used here. FLUSH PRIVILEGES
applies the permissions to the server.
A note on permissions
In the example above, the system account is given all permissions on the database. You may not want to give your application this level of access to the database, once it is in production. MySQL makes it trivial to restrict permissions on individual tables or columns within tables and/or by SQL operation (e.g. the production system account could just be given SELECT
permissions if the application just reads from the database tables).
The database connection settings for a Rails application are stored in a single file called database.yml
, inside the config
directory (which is in turn inside the RAILS_ROOT)
. The freshly-minted database.yml
file (produced by the rails
command) can seem a bit confusing, mainly because it contains a lot of examples and hints. However, after removing comments, it boils down to this:
development: adapter: mysql database: Intranet_development username: root password: host: localhost test: adapter: mysql database: Intranet_test username: root password: host: localhost production: adapter: mysql database: Intranet_production username: root password: host: localhost
This is a YAML (rhymes with "camel") file, which configures the database settings for each of the three Rails' environments: development, test, and production—which is explained in the next section).
YAML, ( "YAML Ain't a Markup Language"), is officially described as a "data serialization language" (see, http://yaml.org/). Its purpose is comparable to that of XML: both YAML and XML are used to define configuration settings, log file formats, or other kinds of structured data. However, YAML has the following benefits over XML:
The YAML syntax used in the database.yml
file defines a YAML mapping from keys to values. (If you've ever worked with a configuration file, the key-value concept should be familiar.) When the file is read by Rails, it is converted into a Ruby hash (c.f. a dictionary or associative array in other languages). The words which are flush with the left of the file ('development', 'test', 'production') are the keys of this top-level hash; in Ruby syntax, the hash looks like this:
{ 'development' => {...}, 'test' => {...}, 'production' => {...} }
Underneath each of these top-level keys is a series of name-value pairs; each series is also converted into a hash. The parent key has this hash as a value. In Ruby syntax, the resulting "hash of hashes" looks like this:
{ 'development' => { 'adapter' => 'mysql', 'database' => 'Intranet_development', 'username' => 'root', 'password' => nil, 'host' => 'localhost' }, 'test' => {...}, 'production' => {...} }
(The 'test' and 'production' sections are truncated for brevity.)
Each sub-hash specifies a database configuration for one of the Rails environments, as described in the next section.
Rails can run an application in different modes; each mode is known as an environment. Each environment is kept isolated from the others, uses a different database, and handles logging and error checking differently. This makes it possible to develop your code without breaking the live application, run tests without wiping records from the live database, and run your application more efficiently in production (amongst other things).
The three environments have different purposes and characteristics:
This is the environment you use when building your application. Logging and error reporting are at their most verbose, making it simpler to track down bugs. This environment uses its own database which is kept isolated from the production database.
This environment is only normally used when running automated tests. The database for this environment is regenerated from scratch each time tests are run, by cloning the structure (not the data) of the development environment.
Rails does a lot of work behind the scenes creating classes and their methods on the fly (which is how it does the clever database reflection discussed later in this chapter). In the production environment, this work is done once when the application starts and cached to save work later (by contrast, in development, it is done on each request). Debugging and logging are also set to a minimum in this environment.
You can configure database settings by editing the section of the database.yml
file named after the environment. For now, we'll just edit the settings for the development environment:
development: adapter: mysql database: 'intranet_development' username: intranet password: police73 socket: /var/run/mysqld/mysqld.sock
You must use spaces, not tabs, in a YAML file: attempting to use tabs in a YAML file will break it completely. For reference, so that you can recognize it in case it happens to you, here's a YAML error caused by an errant tab:
/usr/lib/ruby/1.8/yaml.rb:133:in 'load': syntax error on line 13, col 11: ' adapter: mysql' (ArgumentError)
There is no need to configure the test and production databases at this point: we can leave the default settings as they are until we need these environments.
Each line of the configuration is described in more detail in the table below:
Configuration option |
Example setting |
Description |
---|---|---|
adapter |
|
The type of database to which the application is connected. |
database |
|
The name of the database to use in this environment. The Rails convention is to use the suffix |
username |
|
The username for the system account. |
password |
|
The password for the system account. |
host |
|
If the application needs to connect to the database server over a network, this is the hostname or IP address of the database server. Where the Rails application and the database server are running on the same machine, |
socket |
|
This is an interesting setting, and one which is often overlooked. It is mainly used on *nix machines, where the database connection is made using a Unix-style socket, rather than a network (TCP) connection. In some cases, it may not be possible to create a network connection at all (TCP can be switched off on MySQL on *nix); in this case, specifying a socket location is the only option. The example setting shown here points at the default socket location on Ubuntu. See the section Troubleshooting a MySQL Connection for more details about sockets. |
Although we are using MySQL as our database server, ActiveRecord supports a range of other back-ends. You can specify which by changing the adapter
configuration option to one of these values:
Each adapter has its own set of configuration options: see the Rails documentation for adapter-specific details. (Chapter 3 explains how to locate the Rails documentation on your machine.)
Some adapters have specific requirements, such as the installation of additional Ruby or native libraries. This may restrict your choice of server operating system for running your Rails application. For example, the sqlserver adapter requires the use of ODBC, which may in turn require you to install a variety of ODBC software on your application server (see http://wiki.rubyonrails.org/rails/pages/HowtoConnectToMicrosoftSQLServerFromRailsOnLinux). Make sure you are aware of all the pre-requisite software you need for some of the Rails database adapters.
It is useful to check that the database connection is working before going any further. There's an easy way to do this. Start up a Rails console session using another of the built-in scripts Rails adds to your application called the console. Do this using the command line, by connecting into RAILS_ROOT
and running:
ruby script/console
You should see:
Loading development environment
>>
If you do, Rails has loaded your application's components correctly. The command prompt can now be used to enter commands, which directly manipulate your Rails application, without having to use a browser: very useful for general testing and tinkering. (We'll come back to the console throughout this chapter.) For now, enter this command to test your database connection:
>> ActiveRecord::Base.connection
If the database connection is working correctly, you should see:
=> #<ActiveRecord::ConnectionAdapters::MysqlAdapter:0xb74dbe34 ...>
This has been truncated, as you get a lot of detail back from the console. But providing an ActiveRecord::ConnectionAdapters::MySQLAdapter
instance has been successfully created, you can be happy that the database connection is working.
If the database connection fails, you might see this instead:
Mysql::Error: Can't connect to local MySQL server through socket '/var/run/mysql/mysqld.sock' (2)
...which means the socket location is wrong.
Or:
Mysql::Error: Access denied for user 'intranet'@'localhost' (using password: YES)
...which means the system account does not have access to the server and/or the database.
The next section covers what to do if one of these errors occurs.
If you discover that your MySQL connection isn't working (see the previous section), check the following:
mysql
command line client and the system account, as specified in your database.yml
file. If you can login, it's likely that your database.yml
file contains a typo in the username and/or password. mysql
command line client using the system account, try the command:USE intranet_development;
If you get an error at this point, it means the system account doesn't have the correct level of access to the database. Check the permissions granted to the system account.
| mysql> SHOW VARIABLES LIKE 'socket';
You should get back something like this:
+--------------------+----------------------------------------+
| Variable_name | Value |
+--------------------+----------------------------------------+
| socket | /var/run/mysqld/mysqld.sock |
+--------------------+----------------------------------------+
Now, make sure that the socket setting in database.yml matches the value of the socket variable reported by MySQL.
host
option, ensure that you can connect from the application server to the database server using the mysql
command line client. If you can connect successfully, but your Rails application can't, it may be that the host
setting is wrong in database.yml
.Hopefully, you should be able to fix pretty much any MySQL connection error by following these steps.
18.118.2.225