Vous êtes sur la page 1sur 22

Chapter 4 – ActiveRecord

Chapter 4– ActiveRecord – The Model part of MVC.

ActiveRecord

It’s an implementation of a design pattern ‘Active Record’ (observe the space in between), which
is an Object Relational Mapping(ORM) mechanism.

ActiveRecord is one such implementation of this design pattern which helps us do all our
database tasks (Data Definition and Data Manipulation through its meta programming
capabilities) without we having to write any SQL statement. It represents database tables through
classes and instances of those classes.

A class which wraps around a database table is called a “model”, instances of these classes are
“model instances”. Models encapsulate business logic

Some more examples of ORM implementation are ‘Hibernate’ for Java and ‘Castle’ in .Net

Though ActiveRecord is a ruby library built for Rails, it can be used with other frameworks as
well. But we will stick to rails for now. Just for the information ActiveRecord source code is the
biggest part of Rails total source.

ActiveRecord library supports almost all popular databases such as Oracle, sqlServer, db2,
postgresql, sqlite, Sybase etc.

What happens underneath the ActiveRecord (AR):


1. generates sql
2. the sql is passed to underlying RDBMS
3. the RDBMS compiles this SQL
4. then executes it,
5. returns an enumerable (array like object)
6. creates an ActiveRecord model object for each row.

As one can see, the whole process of SQL execution would be slower as compared to running a
‘stored procedure’ in the database (which is a pre-compiled code). One can always ask, can we
run a ‘stored procedure’ from AR directly?, yes, we can. But as stored procedures are relational
database specific, this could become a limitation.

We can(and often need to) run SQL directly from AR to speed up the process But then one has to
learn writing good SQL queries and implement ANSI SQL so as to make our application
RDBMS agnostic.

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

Before we dive-in learning the nuts and bolts of AR, please make a note of the following points:

1. ActiveRecord is a Model layer, an interface which helps us manages our database. All the
CRUD (Create, Read, Update, Delete) operations can be to be done through AR. The
Relational database can be used merely as a record storage purpose.

2. The code we write here would consist of most of the business logic. Obviously it is very
much likely to be reusable across applications.

3. While working on any application, one should analyze, how far our application needs to
be database agnostic, when to utilize the power of flexibility and when do you need the
speed of execution and when to do the balancing act.

4. ActiveRecord::Migration class is used for Data Definition purposes and


ActiveRecord::Base class is used for Data Manipulation purposes.

I plan to cover following points in this chapter.

1. AR-database connectivity.
2. Conventions over configuration
3. Creating a Model and various CRUD features available in AR.
4. Validations
5. Callbacks
6. Model Associations. One-to-one, One-to-many (w/o eager loading), many-to-many
(using has-and-belongs-to-many and :through options)

Note :
1. We will be creating/altering our relational database schema through migrations (see Chapter
5). But for the sake of keeping focus only on AR ‘model’, we create tables in mySQL directly.

2. In this chapter we will be using ‘ruby script/console’ extensively.


http://wiki.rubyonrails.org/rails/pages/Console The console gives you access to your Rails
Environment where you can interact with the domain model directly. You can inspect domain
models, change values, and save to the database. Use ‘exit’ command to exit from the console
window.

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

1 How AR connects itself to the database

As we have seen earlier in chapter 3, the file ‘database.yml’ has all configuration settings
associated with the database, which ActiveRecord uses to connect to.

<environment>:
adapter: mysql Development, Test or Production
encoding: utf8
database: sample1_development
username: root
password :root
host: localhost

ActiveRecord can connect itself to different databases. The appropriate adapters are required to
connect to them.

The added separation of environment (Development/Test/Prod.) with ActiveRecord as an ORM


tool, gives developers a flexibility to test/deploy there application on different databases

One would wonder why rails prefers to use .yml files over XML. The reason is simplicity
readability (human readable) and usability of the .yml structure over XML.

Observe the two formats having the same contents:

.XML File .YML File


<user id="boby" on="cpu1"> boby:
<first_name>Sunil</first_name> computer: cpu1
<last_name>Kelkar</last_name> first_name: Sunil
<user_name>svk2006</user_name> last_name: Kelkar
</user> user_name: svk2006

Pl observe the .yml file as a ‘key – value’ pair. Ruby syntax can very easily convert this file to a
hash table and carry out the connectivity. http://yaml4r.sourceforge.net/cookbook/ is a great
source for those interested in knowing all about YML files.
Rails uses YAML files extensively to specify fixtures which we will see in the coming sessions..

ActiveRecord::Base.establish_connection is the method which establishes the connection to the


database. It accepts a hash as input where the :adapter key must be specified with the name of a
database adapter (in lower-case)
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => "root",
:password => "root",
:database => "sample1"
)
Rails 2.0 Notes:
Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

2. Conventions over configuration:

For the magic of ActiveRecord to work, you must name our database tables and columns
according to specific conventions.

Model class name should be in CamelCase and is mapped to the Table which is a pluralized
form of the model class name.

E.g. If the model name is ‘User’, rails would assume the table name is ‘users’ (table name is
lower case). If our model class is ‘Person’, mapping table name would ‘people’, a pluralizing of
the word ‘Person’. (Tables are ‘plural’ and the associated model is ‘singular’)

How does rails knows this? With the help of ‘Inflector’ class, we get the answer.

c:\sample1> ruby script/console


Loading development environment.

>> Inflector.pluralize('test')
=> "tests"
>> Inflector.pluralize('mouse')
=> "mice"
>> Inflector.pluralize('person')
=> "people"
>> "company".pluralize
=> companies

B. Primary Key name should always be ‘id’, which should be an auto-incremented integer, case
sensative.

C. Foreign keys join database tables. When you need a foreign key field in a table, the key takes
the form "{singular foreign table name}_id".
E.g. person_id with an English singular and an _id suffix.

D. If you have fields “created_on” or “created_at” in your table, AR will automatically


timestamp them on initial row create.IF you have fields “updated_on” or “updated_at” in your
table, AR will automatically timestamp them whenever a modification is made to the record. Use
‘datetime’ as the column type, not timestamp. These fields should not have default values, rails
takes care of that for you. These fields should be able to be set to NULL

E. For association tables (also known as intersection tables) that resolve many-to-many
relationships, we use the following naming convention: {name of first entity}_{name of second
entity} e.g. products_categories ( explained with example later in the chapter)

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

Note: This convention adds to standardization which in turn adds to the speedy development. But
still, one would wonder, what if one has to bypass/override these conventions, due to some
practical problems(say, incase of some tables already exists).Yes, there is a way. I have listed
some overrides at the end of this chapter.

Create a Model:

Lets us carry out one simple exercise to prove our point.


1. We need to create one table (users) and one model (User)
2. The rails convention will automatically map model (User) on the table (users).
3. We will use the ‘console’ script to add data to this table without writing any SQL query.

1. Pl create one table in mySql with the following structure (do not worry about the size of
individual fields right now, take the defaults)

users
id integer
first_name string
last_name string
user_name string
login string
password string
phoneNo integer

2) We create a model called ‘User’:

railsApps\sample1> ruby script/generate model User

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

You should get the following output:

You will observe, no. of folders and files getting created. Do not bother too much about ‘test’,
‘app’ and ‘db’ folders/files right now. Let’s just focus on the app/models folder, and ‘user.rb’ file.

user.rb

class User < ActiveRecord::Base

end

ActiveRecord::Base is the class which all models inherit. This inheritance gives
our User class, a tremendous amount of functionality. As we learn further we will realize that
these model classes will contain all the business logic of our applications.

In this case, ‘User’ class automatically maps to ‘users’ tables as per rails conventions.

3) Now let’s play around our model, ‘User’:

railsApps\sample1> ruby script/console


Loading development environment.

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

>> user1 = User.new


>> user1.first_name = "Satish"
>> user1.last_name = "Talim"
>> user1.email = "satish.talim@gmail.com"
>> user1.save
=>true

>> user2 = User.create(:first_name => ‘Marcos’ , :last_name => ‘Ricardo’)


=>true

# Notice the difference between New and Create


# The ‘new’ method, creates a new record in memory followed by a ‘save’ method to save it to
the database where as ‘Create’ not only generates but saves a new record to the database.

>> user.update_attributes(:first_name => ‘Luiz’, :last_name => ‘Biagi’ )


==>true

# You can go on adding / updating few more records this way.

Objects ‘user1’ and ‘user2’ are mapped on two records of ‘users’ table. While we are executing
these simple instructions, underneath, AR is doing the magic of generating/executing the SQL
statements. These operations are logged in a log file.

A note on Logging and Log Files

Please open /log/development.log file in a separate window and find the SQL generated.

Rails has logging built right into the framework, it exposes a Logger object to all the code in a
Rails application. Whenever we execute operations in AR, it generates a log of activities.
Logs help us monitor/manage our application behavior/performance.

A development environment will log to ‘log/development.log’, an application under test to


‘log/test.log’, and a production application to ‘log/production.log’.

We can generate log messages at the warning, info, error, and fatal levels.

log/development.log:

If you observe these SQL statement generated, it has some cryptic sequence of characters known
as color escape sequences that are used by default. Simply set colorize_logging to false to
make it more readable output:

ActiveRecord::Base.colorize_logging = false

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

Or better still, open config/environment.rb file and at the end of the file(last line), you type
the above statement and save the file. We need to ‘exit’ from the console window since we
have changed the settings and enter again to see the effect.

Note: After every ruby console command execution, continue to refresh this log file and observe
the SQL generated by ActiveRecord.

Now that we have done the log file setting, let’s continue with the model discussions.

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

Use Finder methods to retrieve records from the database:

>>User.find(1) # find selects by 'id' (default integer primary key)


>># find with ids 2, 4, and 7
>> User.find(1,4,7)

>> user = User.find(:all)


>> user.each{ |rec| puts rec.first_name}
>> user1 = User.find(:first) #will fetch you the first record

Note: find(:all) would return an array like object which we can iterate using ‘each’ method.
I hope you get some rough idea of, when a request from the browser is made, how the model
retrieves the desired records from the database.

One can use SQL directly:

>> User.find_by_sql “SELECT usr_name, email FROM users”

Dynamic Finder methods

Look at the method ‘find_by_first_namel’. ActiveRecord adds a dynamic finder for each of the
attributes available in the table.

>> User.find_by_first_name ‘Satish’

A Tip: Dynamic finder methods

While using something like User.find_by_user_name is very readable and easy, it is an overhead
to rails,
ActiveRecord dynamically generates these methods within method missing and this can be quite
slow.
Using MyModel.find_by_sql directly, or MyModel.find, is more efficient.

Finding records based on ‘conditions’

>> User.find :all, :conditions => “first_name LIKE ‘S%’ ” , :limit => 10

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

Tip:Optimize on execution time. We should retrieve only the information that we need. A lot of
execution time can be wasted by running selects for data that is not used.

Explore ‘:select’ option (extract only those fields we are going to use) , :limit and :offset options
(if the record size is large, this option is a must)

Custom Methods

user.rb

class User < ActiveRecord::Base

def full_name
name = first_name + ‘ ‘ + last_name
end

def self.find_all_ordered
find :all, :order => ‘last_name, first_name’
end

end

Just observe the custom methods carefully. No where we are writing any ruby statements to
display the records. That’s the job of ‘Views’ which we will learn later. I can use the same class
for multiple web applications as this class can become generic.
‘Reusability’ is the core of Object Orientated Programming.

Validations

Adding validations to our code means, the record won't be created or saved unless these
conditions are met or satisfied. Model-based validations help make data within our database
stays consistent.

Change ‘user.rb’ as shown below:

User.rb

class User < ActiveRecord::Base


EMAIL_EXP = /^ [A-Z0-9._%-]+@[A-Z0-9.-]+\ . [ A-Z] {2,4} $/i
validates_format_of :email, :with => EMAIL_EXP
validates_presence_of :user_name, :message => “User name can not be Blank”
validates_uniquness of :user_name
validates_numericality_of :phoneNo, :allow_nil => true
end

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

Observe the validation validates_numericality_of with :allow_nil. It skips validation if


attribute is nil (default is false). Note that for fixnum and float columns empty strings are
converted to nil.

Since we have modified the User.rb, to reload the class, exit from the console and re-enter the
console window.

>> user = User.new


>>User.new(:phoneNo => nil).valid?
=> true
>> user.save
>> false

>> user.errors

An Errors object is automatically created for every Active Record.

User2 = User.new("first_name" => "David", "phoneNo" => "what?")


User2.save # => false (and doesn't do the save)
User2.errors.empty? # => false
User2.errors.count
User2.errors.on "user_name" # => "User name can not be Blank"
User2.errors.on "email"
User2.errors.each_full {|msg| puts msg}

For more samples and various validation options, a further reading is advised
http://rails.rubyonrails.com/classes/ActiveRecord/Validations/ClassMethods.html

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

Callbacks

The callbacks are similar to triggers in relational databases.

In any of the business application, ‘validation’ and ‘authentication’ of a record could be different
activities/processes. Validations could be just related to the filed levels, while authentication
would be applied to the entire form. E.g. In any credit card transaction, we can add ‘validations’
to our model to check if name, card no, expiry date etc are entered properly, but the actual
‘authenticity’ of the card(getting a confirmation for the validity of the card ) needs to be carried
out , before the actual transaction takes place. This ‘pre process’ can be done using callbacks.
The ‘post process’ could be to send emails to the customer with the status of the transaction.
Even this we call as Callbacks.

During the application life cycle, we come across the following events:

after_validation After all validation procedures are complete


after_validation_on_create After validation of new objects
after_validation_on_update After validation of existing objects being
updated
before_validation Before the object is validated
before_validation_on_create Before validation of new objects
before_validation_on_update Before validation of existing objects being
updated
before_create Before the object is added to the database
before_destroy Before an object is destroyed
before_save Before an object is saved to the database,
either by way of creation or an update
before_update Before an object is modified in the database

Calculations

Do you want to get maximums, minimums, averages, or sums for data in your tables?
ActiveRecord’s Calculations make these all possible. Most can be customized pretty deeply with
extra options, so go read about them.

http://api.rubyonrails.org/classes/ActiveRecord/Calculations/ClassMethods.html

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

Model Associations

We are aware that web applications contain bunch of tables and they are ‘associated’ (related)
with each other. With ‘normalization’ as the key, we avoid redundancy. These associations are of
different types e.g.one-to-one, one-to-many, many-to-many, polymorphic etc. ActiveRecord as of
today, can not read these associations automatically, we as programmers, need to define them in
models, so we call it Model Associations.

One-to-one Association

For the sake of example, pl assume, the user (or author), in our ‘users’ table can write at
most one ‘article’. To set this association, we need to

1. Have 2 tables, ‘users’ and ‘articles’ (we already have ‘users’ table)
2. We need 2 models ‘User’ and ‘Article’ to map on the above 2 tables (we already have
‘User’ model/class).
3. Define the association between these models.
4. See how the above association works in AR by adding/updating records in these tables.

1) Define table ‘articles’ (we already have ‘users’)

users
id integer
first_name string
last_name string
user_name string
login string articles
password string id integer
user_id integer
title string
created_on datetime

Pl create the ‘articles’ table in mySql as described above. The ‘user_id’ column is our foreign
key in ‘articles’ table (as per rails naming convention).

2) Now that the tables are set, we need our model ‘Article’ and in that we set the association.
railsApps\sample1> ruby script/generate model Article

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

3) Edit both the model classes and add the following association methods

user.rb article.rb

class User < ActiveRecord::Base class Article < ActiveRecord::Base


has_one :article belongs_to :user # foreign key user_id
end end

has_one :article and belongs to :user are the methods (not method definitions), that take symbol
as a parameter. The belongs_to method adds an association, called user, to article,

Please note that, :articles is singular, since the association is of the form ‘has_one’, in case
association is one-to-many, it would become
(has_many :articles). >> a1 = Article.new
>> a1.title = “Instant Ruby”
>> user = User.find(1)
railsApps\sample1> ruby script/console >> user.articles << a1
Loading development environment >> user.save
>>user

** Observe the SQL being generated in each case (use the log file)

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

One-to-many Association

Consider a case where ‘One User can write many Articles’. This indicates, we have a
one-to-many association.

In order to understand this association, we will be doing the following:

1. Create 2 tables, ‘users’ and ‘articles’ ( both tables are available)


2. We need 2 models ‘User’ and ‘Article’ to map on the above 2 tables.
3. Define the association between these models
4. See how the above association works in AR by adding/updating records in these tables.

1) Define table ‘articles’ (we already have ‘users’)

users
id integer
first_name string
last_name string
user_name string
login string articles
password string id integer
user_id integer
title string
created_on datetime

2) Its time to update our models. Ideally, I would destroy the previously created model and
create a new one with the same name as :

railsApps\sample1> ruby script/destroy model User Give the same treatment to


‘Article’ model.
This ensures all previously created references are deleted. This does *not* delete our tables.
Now create both the models with “ruby script/generate model User”, same of Article.

3) Define the correct association between the models.


user.rb article.rb
class User < ActiveRecord::Base class Article < ActiveRecord::Base
has_many :articles
end belongs_to :user
end

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

belongs to :user and has_many :articles are the methods (not method definitions) that take
symbol as a parameter. The belongs_to method adds an association, called user, to article,

Please note that, :articles is plural, since the association is of the form ‘has_many’, in case
association is one-to-one, it would become (has_one :article).

Check out the following in your ruby console: DO CHECK the sql statements generated after
execution of these instructions too.

railsApps\sample1> ruby script/console >> a1 = Article.new


Loading development environment >> a1.title = “Instant Ruby”
>> user = User.find(1)
>> user.articles << a1
>> user.save
>>user

From the above example, its quite evident that the parent model instance (‘user’) gets the
child model methods (‘articles’)

We can add/update records even this way

>> user.articles.create( :title => “The Ruby Way”)

Finder methods work as before, but note the association.

>> user = User.find(1)


>> user.articles.count
>> user.articles

** Observe the SQL being generated in each case (use the log file).

One more question arises, and that is when we delete a ‘user’ from the users table, ‘what happens
to the ‘article records’, as there is an association, do they get deleted automatically? NO.

The solution is to explore the Help files  and you get the way out, we use the dependency
option , :dependent.

user.rb

class User < ActiveRecord::Base


has_many :articles, :dependent => :destroy
end

>> u = User.create(:first_name => “John”, :last_name => “Alter”)


>> u.articles.create(:title => “Core Java”)
>>u.articles.create(:title => “Developing Java Applications”)
Rails 2.0 Notes:
>>u.articles
Sunil Kelkar
>>u.destroy sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

When you refresh the console, you would see the user ‘John’ and his all authored books are
deleted from ‘articles’ table.

Eager loading

The ActiveRecord documentation says: “Eager loading is a way to find objects of a certain class
and a number of named associations along with it in a single SQL call. This is one of the easiest
ways of to prevent the dreaded 1+N problem in which fetching 100 posts that each need to
display their author triggers 101 database queries. Through the use of eager loading, the 101
queries can be reduced to 1.”

To cut this story short, suppose we want to fetch all articles of a specific user, with the current
knowledge we would carry out operations this way.

>> user = User.find(:first)


>> user.articles

You will notice that 2 queries are fired to fetch the result set. A better way to go about it using,
eager loading, using :include option
>>user1 = User.find(:first, :include => :articles)
>>user1.articles

In one query, we get the result set, did you observe the ‘LEFT OUTER JOIN’?

One thing, we need to remember though, ActiveRecord ignores the ‘:select’ directive if we use
‘:include’. This could be a little overhead. But there is always an alternative. Use ‘:joins’ option

>>user2 = User.find(:first,
:select => “users.first_name, articles.title”,
:joins => "left outer join articles on users.id = articles.user_id")

>>user2.first_name
>>user2.title

The query generated for the ‘find’ is as follows:

SELECT users.first_name, articles.title FROM `users` left outer join articles on users.id =
articles.user_id LIMIT 1

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

Many-to-many Association (using has_and_belongs_to_many)

Continuing our model discussion, in practice, we know a ‘user’ (or author) can write
‘many articles’ and one ‘article’ can have ‘many users(or authors)’.

In design terms we call this as ‘many-to-many-association’. In order to set the above


association, we shall
1. use a method has-and-belongs-to-many (or ‘habtm’ when we talk about it)
2. we need to create a new concatenation table (joining the names of the tables in the
alphabetical order), which should contain the foreign keys of the target tables.
(conventions, you see).

So, please set your tables and the model classes as shown below.
Note: Continue to observe and study the SQL getting generated in log files.

users
id integer
first_name string
last_name string
user_name string
login string
password string
articles_users
user_id integer
article_id integer

articles
id integer article.rb
class Article < ActiveRecord::Base
title string has_and_belongs_to_many :users
created_on datetime end

user.rb
class User < ActiveRecord::Base
has_and_belongs_to_many :articles
end

>> author1 = User.create(:first_name => “Author – 1”)


>> author2 = User.create(:first_name => “Author – 2”)

>> a1 = Article.create(:title => “Book – 1”)


>> a2 = Article.create(:title => “Book – 2”)

>> author1.articles << a1


>> author1.articles << a2
Rails 2.0 Notes:
Sunil
>> Kelkar << author2
a1.authors sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

I am going to dive a little further and explain the same association but with a different database
design and a model method option (:through).

Many-to-many Association (using :through)

we again need to modify our design a little bit, (Its an agile world, change is the only constant,
you see) 

We will carry out 2 things


1. Create one more table ‘user_articles’ and *NOT* users_articles.
2 Create a model class ‘UserArticle’ and update the correct relationship among these
models.

users
id integer
first_name string
last_name string
user_name string
login string
password string
user_articles
user_id integer
article_id integer

articles
id integer
title string
created_on datetime

railsApps\sample1> ruby script/generate model user_article

user.rb user_article.rb

class User < ActiveRecord::Base article.rb


class UserArticle < ctiveRecord::Base
has_many :user_articles belongs_to :user
end class Article < ActiveRecord::Base
belongs_to :article
has_many
end :user_ articles
end
Note: The plural user_articles and

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

*not* user_article

I am assuming, you have added few records in users and articles tables.

Assume we have to find out all the users( authors) for a specific article.
Ideally we should get result in two steps viz
>> a = Article.find(1) # the first article in the table.
>> a.users # and this should fetch all the users for that article.

But with the above mapping, our steps would be

>> a = Article.find(1) # the first article in the table.


>> a.user_articles # would fetch us an array, lastly
>>a.user_articles[0].user # we get the actual user name/s

Did you see, we needed one extra steps to carry out the job? Did you observe the query
generated, well it needs to be optimized too.

ActiveRecord has a solution to this, using has_many :through relationship.

Through associations allow for one model to be accessed through an intermediary association

Modify our model Article to look like this:

article.rb

class Article < ActiveRecord::Base


has_many :user_ articles
has_many :users, :through => user_articles
end

Now carry out the tasks by reloading the development environment

The query will have an Inner join, the way it should be. We can even
add another user (author) to the same article
>> a = Article.find(1)
>> a.users
>> a.users << User.find(3) # this will insert one user for that article by adding one record in
#the user_articles table

Assignment:

1. Discuss the advantages of using option: through


2. Explore the web/books and discuss Polymorphic associations (I plan to add notes on
this, in the second week of our course)
3. Read and Discuss about ActiveRecord ‘Transactions’
Rails (http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html)
2.0 Notes:
Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

TIPS: Overriding conventions.


1. An alternate Table Name: If you don't want your table name to be plural, you can
override it in your model class file using the ‘set_table_name’ method.

class User < ActiveRecord::Base


set_table_name "accounts" # by convention it would be ‘users’
# alternatively we can say
# self.table_name = "accounts"
end

2. An alternate Primary Key

class User < ActiveRecord::Base


set_primary_key "userID" # by convention it would be ‘id’
# but must be an Integer key
# alternatively we can also say self.primary_key “userID”
end

3. If we desire to ‘globally’ turn off the pluralization, open config/environment.rb


file and at the end of the file, write

ActiveRecord::Base.pluralize_table_names = false

Discuss: When you don’t want to follow any of the conventions, where are you saving
time, or adding simplicity/maintainability to your code?

Read more: http://wiki.rubyonrails.com/rails/pages/HowToUseLegacySchemas

As ActiveRecord is the biggest part of Rails 2.0 , I have tried to cover maximum details, I
thought are good to start with. Let us turn our attention now to Data Definition part of
ActiveRecord with Migrations which is our next chapter.

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com
Chapter 4 – ActiveRecord

Assignment :

Discuss :
1. Explore the concept of ‘SQL injection’ and how rails can protect itself from it, prove with an
example.

2. Log files track every activity happening in AR., Is it worth it? What are the impacts when
application goes live.

3. We know that the field level ‘validations’ are done at the client side (Using java script), then
what’s the advantage of having ‘validations’ in models?

4. Explore ‘Finder’ methods further ( :conditions, :order, :group, :limit, :offset, :joins, :include,
:select, :readonly etc)
http://www.railsbrain.com/api/rails-2.0.2/doc/index.html?a=M001686&name=find

Workout:
5. Explore conditional searching, check whether, extracting records based on search conditions,
result in ‘case sensitive’ results?

A) Make use of following validations

1. validates_length_of :password,
:minimum => 8 # more than 8 characters
:maximum => 16 # no more than 16 characters
:in => 8..16 # between 8 and 16 characters
:too_short => ' password is too short'
:too_long => ‘ password is too long'
2. validates_confirmation_of :password
3. validates_acceptance_of :first_name

B) If all such validations are included, in what order are they carried out?

6. Write 2 custom methods to find out ‘next’ and ‘previous’ records in the model
(record ‘id’ will be passed as an argument).

Note 1) Keep http://www.railsbrain.com or http:://www.noobkit.com handy


2) All validations take the extra options :message and :on
3) You would observe in rails, many methods take an “options” hash as a parameter, rather
than having dozens of individual parameters

TIP: When available use the built-in classes and methods, rather than developing your own.

Rails 2.0 Notes:


Sunil Kelkar sunilkelkar@gmail.com

Vous aimerez peut-être aussi