aboutsummaryrefslogtreecommitdiffstats
path: root/railties/doc/guides/activerecord
diff options
context:
space:
mode:
Diffstat (limited to 'railties/doc/guides/activerecord')
-rw-r--r--railties/doc/guides/activerecord/active_record_basics.txt120
-rw-r--r--railties/doc/guides/activerecord/association_basics.txt3
-rw-r--r--railties/doc/guides/activerecord/finders.txt42
3 files changed, 159 insertions, 6 deletions
diff --git a/railties/doc/guides/activerecord/active_record_basics.txt b/railties/doc/guides/activerecord/active_record_basics.txt
new file mode 100644
index 0000000000..60ee1ef7b7
--- /dev/null
+++ b/railties/doc/guides/activerecord/active_record_basics.txt
@@ -0,0 +1,120 @@
+ActiveRecord Basics
+=================================
+This guide will explain in detail how the ActiveRecord design pattern is used inside Ruby on Rails to make communication with the database clear and easy to understand.
+The intent of this guide is to explain the ActiveRecord implementation used by Rails though easy to understand examples, metaphors and detailed explanations of the actual Rails source code.
+After reading this guide readers should have a strong grasp of the ActiveRecord concept and how it can be used with or without Rails. Hopefully, some of the philosophical and theoretical intentions discussed here will also make them a stronger and better developer.
+== ORM The Blueprint of ActiveRecord
+If ActiveRecord is the engine of Rails then ORM is the blueprint of that engine. ORM is short for “Object Relational Mapping” and is a programming concept used to make structures within a system relational. ORM seeks to give semantic meaning to the associations between elements of the system for example tables within a database.
+As a thought experiment imagine the components that make up a typical car. There are doors, seats, windows, engines etc. Viewed independently they are simple parts, yet when bolted together through the aid of a blueprint, the parts become a more complex device. ORM is the blueprint that describes how the individual parts relate to one another and in some cases infers the part’s purpose through the way the associations are described.
+== ActiveRecord The Engine of Rails
+ActiveRecord is a metaphor used to access data within a database. The name “Active Record” was coined by Martin Fowler in his book “Patterns of Enterprise Application Architecture”. ActiveRecord is a conceptual model of the database record and the relationships to other records.
+As a side note, from now when I refer to ActiveRecord I’ll be referring to the specific Rails implementation and not the design pattern in general. I make this distinction because, as Rails has evolved so too has the Rails specific implementation of their version of ActiveRecord.
+Specifically, the Rails ActiveRecord pattern adds inheritance and associations. The associations are created by using a DSL (domain specific language) of macros, and a STI (Single Table Inheritance) to facilitate the inheritance.
+Rails uses ActiveRecord to abstract much of the drudgery or C.R.U.D (explained later) of working with data in databases. Using ActiveRecord Rails automates the mapping between:
+* Classes & Database Tables
+* Class attributes & Database Table Columns
+For example suppose you created a database table called cars:
+[source, sql]
+-------------------------------------------------------
+mysql> CREATE TABLE cars (
+ id INT,
+ color VARCHAR(100),
+ doors INT,
+ horses INT,
+ model VARCHAR(100)
+ );
+-------------------------------------------------------
+Now you created a class named Car, which is to represent an instance of a record from your table.
+[source, ruby]
+-------------------------------------------------------
+class Car
+end
+-------------------------------------------------------
+As you might expect without defining the explicit mappings between your class and the table it is impossible for Rails or any other program to correctly map those relationships.
+[source, ruby]
+-------------------------------------------------------
+>> c = Car.new
+=> #<Class:0x11e1e90>
+>> c.doors
+NoMethodError: undefined method `doors' for #<Class:0x11e1e90>
+ from (irb):2
+-------------------------------------------------------
+Now you could define a door methods to write and read data to and from the database. In a nutshell this is what ActiveRecord does. According to the Rails API:
+“Active Record objects don‘t specify their attributes directly, but rather infer them from the table definition with which they‘re linked. Adding, removing, and changing attributes and their type is done directly in the database. Any change is instantly reflected in the Active Record objects. The mapping that binds a given Active Record class to a certain database table will happen automatically in most common cases, but can be overwritten for the uncommon ones.”
+Lets try our Car class again, this time inheriting from ActiveRecord.
+[source, ruby]
+-------------------------------------------------------
+class Car < ActiveRecord::Base
+end
+-------------------------------------------------------
+Now if we try to access an attribute of the table ActiveRecord automatically handles the mappings for us, as you can see in the following example.
+[source, ruby]
+-------------------------------------------------------
+>> c = Car.new
+=> #<Car id: nil, doors: nil, color: nil, horses: nil, model: nil>
+>> c.doors
+=> nil
+-------------------------------------------------------
+
+This wrapper implements attribute accessors, callbacks and validations, which can make the data more powerful.
+- Validations
+ * create!
+ * validates_acceptance_of
+ * validates_associated
+ * validates_confirmation_of
+ * validates_each
+ * validates_exclusion_of
+ * validates_format_of
+ * validates_inclusion_of
+ * validates_length_of
+ * validates_numericality_of
+ * validates_presence_of
+ * validates_size_of
+ * validates_uniqueness_of
+ - Callback
+ * (-) save
+ * (-) valid
+ * (1) before_validation
+ * (2) before_validation_on_create
+ * (-) validate
+ * (-) validate_on_create
+ * (3) after_validation
+ * (4) after_validation_on_create
+ * (5) before_save
+ * (6) before_create
+ * (-) create
+ * (7) after_create
+ * (8) after_save
+
+Rails further extends this model by giving each ActiveRecord a way of describing the variety of ways records are associated with one another. We will touch on some of these associations later in the guide but I encourage readers who are interested to read the guide to ActiveRecord associations for an in-depth explanation of the variety of ways rails can model associations.
+- Associations between objects controlled by meta-programming macros.
+
+== Philosophical Approaches & Common Conventions
+Rails has a reputation of being a zero-config framework which means that it aims to get you off the ground with as little pre-flight checking as possible. This speed benefit is achieved by following “Convention over Configuration”, which is to say that if you agree to live with the defaults then you benefit from a the inherent speed-boost. As Courtneay Gasking put it to me once “You don’t want to off-road on Rails”. ActiveRecord is no different, while it’s possible to override or subvert any of the conventions of AR, unless you have a good reason for doing so you will probably be happy with the defaults. The following is a list of the common conventions of ActiveRecord
+
+
+ActiveRecord is the default model component of the Model-view-controller web-application framework Ruby on Rails, and is also a stand-alone ORM package for other Ruby applications. In both forms, it was conceived of by David Heinemeier Hansson, and has been improved upon by a number of contributors. --wikipedia
+
+ - Naming Conventions
+ - Class Names are Singular
+ - Tables names are the plural name of the class name
+ - Tables contain an identity column named id
+ - ids
+== ActiveRecord Magic
+ - timestamps
+ - updates
+
+== How ActiveRecord Maps your Database.
+- sensible defaults
+- overriding conventions
+
+== Growing Your Database Relationships Naturally
+
+== Attributes
+ - attribute accessor method. How to override them?
+ - attribute?
+ - dirty records
+ -
+== ActiveRecord handling the CRUD of your Rails application - Understanding the life-cycle of an ActiveRecord
+
+== Validations & Callbacks \ No newline at end of file
diff --git a/railties/doc/guides/activerecord/association_basics.txt b/railties/doc/guides/activerecord/association_basics.txt
index df89cfb531..695b834652 100644
--- a/railties/doc/guides/activerecord/association_basics.txt
+++ b/railties/doc/guides/activerecord/association_basics.txt
@@ -1085,7 +1085,8 @@ The +_collection_.delete+ method removes one or more objects from the collection
@customer.orders.delete(@order1)
-------------------------------------------------------
-WARNING: The +_collection_.delete+ method will destroy the deleted object if they are declared as +belongs_to+ and are dependent on this model.
+WARNING: Objects will be in addition destroyed if they're associated with +:dependent => :destroy+, and deleted if they're associated with +:dependent => :delete_all+.
+
===== +_collection_=objects+
diff --git a/railties/doc/guides/activerecord/finders.txt b/railties/doc/guides/activerecord/finders.txt
index d1169ffdd4..e81fa23e3a 100644
--- a/railties/doc/guides/activerecord/finders.txt
+++ b/railties/doc/guides/activerecord/finders.txt
@@ -192,7 +192,7 @@ Readonly is a find option that you can set in order to make that instance of the
[source, ruby]
Client.find(:first, :readonly => true)
-If you assign this record to a variable `client` calling the following code will raise an ActiveRecord::ReadOnlyRecord
+If you assign this record to a variable `client` calling the following code will raise an ActiveRecord::ReadOnlyRecord:
[source, ruby]
client = Client.find(:first, :readonly => true)
@@ -273,14 +273,33 @@ When you define a has_many association on a model you get the find method and dy
== Named Scopes
-There was mention of named scopes earlier in "First, Last and All" where we covered the named scopes of `first`, `last` and `all` which were aliases of `find(:first)`, `find(:last)`, `find(:all)` respectively. Now we'll cover adding named scopes to the models in the application. Let's say we want to find all clients who are not locked to do this we would use this code:
+In this section we'll cover adding named scopes to the models in the application. Let's say we want to find all clients who are male we would use this code:
+
+[source, ruby]
+class Client < ActiveRecord::Base
+ named_scope :males, :conditions => { :gender => "male" }
+end
+
+And we could call it like `Client.males` to get all the clients who are male.
+
+If we wanted to find all the clients who are active, we could use this:
[source,ruby]
class Client < ActiveRecord::Base
- named_scope :unlocked, :conditions => { :locked => false }
+ named_scope :active, :conditions => { :active => true }
end
-We would call this new named_scope by doing `Client.unlocked` and this will do the same query as if we just used `Client.find(:all, :conditions => ["unlocked = ?", false])`. Please be aware that the conditions syntax in named_scope and find is different and the two are not interchangeable. If you want to find the first client within this named scope you could do `Client.first.unlocked`. This is possible because named scopes are stackable.
+We would call this new named_scope by doing `Client.active` and this will do the same query as if we just used `Client.find(:all, :conditions => ["active = ?", true])`. Please be aware that the conditions syntax in named_scope and find is different and the two are not interchangeable. If you want to find the first client within this named scope you could do `Client.active.first`.
+
+and then if we wanted to find all the clients who are active and male we could stack the named scopes like this:
+
+[source, ruby]
+Client.males.active
+
+If you would then like to do a `find` on that subset of clients, you can. Just like an association, named scopes allow you to call `find` on a set of records:
+
+[source, ruby]
+Client.males.active.find(:all, :conditions => ["age > ?", params[:age]])
Now observe the following code:
@@ -293,11 +312,20 @@ What we see here is what looks to be a standard named scope that defines a metho
[source, ruby]
class Client < ActiveRecord::Base
- named_scope :recent, lambda { { :conditions => ["created_at > ?", 2.weeks.ago] } } }
+ named_scope :recent, lambda { { :conditions => ["created_at > ?", 2.weeks.ago] } }
end
And now every time the recent named scope is called, because it's wrapped in a lambda block this code will be parsed every time so you'll get actually 2 weeks ago from the code execution, not 2 weeks ago from the time the model was loaded.
+In a named scope you can use `:include` and `:joins` options just like in find.
+
+[source, ruby]
+class Client < ActiveRecord::Base
+ named_scope :active_within_2_weeks, :joins => :order, lambda { { :conditions => ["orders.created_at > ?", 2.weeks.ago] } }
+end
+
+This method called as `Client.active_within_2_weeks` will return all clients who have placed orders in the past 2 weeks.
+
If you want to pass a named scope a compulsory argument, just specify it as a block parameter like this:
[source, ruby]
@@ -316,6 +344,7 @@ This will work with `Client.recent(2.weeks.ago)` and `Client.recent` with the la
Remember that named scopes are stackable, so you will be able to do `Client.recent(2.weeks.ago).unlocked` to find all clients created between right now and 2 weeks ago and have their locked field set to false.
+
== Existance of Objects
If you simply want to check for the existance of the object there's a method called `exists?`. This method will query the database using the same query as find, but instead of returning an object or collection of objects it will return either true or false.
@@ -387,3 +416,6 @@ Thanks to Mike Gunderloy for his tips on creating this guide.
=== Thursday, 09 October 2008
1. Wrote section about lock option and tidied up "Making it all work together" section.
2. Added section on using count.
+
+=== Tuesday, 21 October 2008
+1. Extended named scope guide by adding :include and :joins and find sub-sections.