Rails Counter Cache


Counter Cache is a mechanism to cache the counts of associated model.Enabling counter cache will simply make Rails to increment and decrement the counter of associated objects. Whenever you need to execute size on ActiveRecord, Rails will use the cached counter.

Necessary steps.

  1. Add the counter_cache column as an integer.
  2. Make sure that the column is set to disallow null values and defaults to 0.
  3. Reset the counters for existing records. The reset_counters method is not smart enough to take an array of ids, so you have to call it for each record you want updated.

Example:

class Organization < ActiveRecord::Base
    has_many :seasons
  end

  class Season < ActiveRecord::Base
    belongs_to :organization, :counter_cache => true
  end

That's it.

Cheers!!!


the best way to set default value in ActiveRecord?


  1. default_scope will initialize values for new models, but then that will become the scope on which you find the model. If you just want to initialize some numbers to 0 then this is not what you want.
  2. Defining defaults in your migration also works part of the time… As has already been mentioned this will not work when you just call Model.new.
  3. Overriding initialize can work, but don’t forget to call super!
  4. Using a plugin like phusion’s is getting a bit ridiculous. This is ruby, do we really need a plugin just to initialize some default values?
  5. Overriding after_initialize is deprecated as of Rails 3. When I override after_initialize in rails 3.0.3 I get the following warning in the console:

Delete everything from all tables (in Activerecord)


Put this code in seed file and run rake db:seed

ActiveRecord::Base.establish_connection
ActiveRecord::Base.connection.tables.each do |table|
# MySQL
ActiveRecord::Base.connection.execute(“TRUNCATE #{table}”)

# SQLite
# ActiveRecord::Base.connection.execute(“DELETE FROM #{table}”)
end

OR

rake db:reset
It recreates your table from migrations
OR

rake db:schema:dump
rake db:schema:load

OR

rake db:drop:all
rake db:create:all

I hope it would help.
Cheers..!!!

Manual active record db connection


Guy’s quick tour, how to connect standalone ruby file to mysql datababase. You can follow steps to understand procedure OR clone my working sample example active recored connection

1. Install relevant gems.
sudo gem install activerecord
sudo gem install yaml_db
sudo gem install logger

2. Create a ruby file and add below code.

require ‘rubygems’
require ‘active_record’

ActiveRecord::Base.establish_connection(
:adapter => ‘mysql’,
:database => ‘test’,
:username => ‘root’,
:password => ”,
:host => ‘localhost’)

when we run this file from rails console it should run without any error and output.

3. Now create table LOCATIONS in test database and insert some row.

mysql> create table locations(name varchar(100), city varchar(100));
Query OK, 0 rows affected (0.60 sec)

mysql> show tables;
+—————-+
| Tables_in_test |
+—————-+
| locations |
+—————-+
1 row in set (0.28 sec)

mysql> insert into locations(name,city) values(‘Sanyam’,’Bettiah’);
Query OK, 1 row affected (0.12 sec)

mysql> insert into locations(name,city) values(‘Sanyam’,’Bettiah’);
Query OK, 1 row affected (0.21 sec)

mysql> select * from locations;
+——–+———+
| name | city |
+——–+———+
| Ankit | Asansol |
| Sanyam | Bettiah |
+——–+———+
2 rows in set (0.00 sec)

4. Add ruby class and inherit ActiveRecord::Base, So we can perform database operation.

class Location < ActiveRecord::Base
end

5. Add initialize action to access database and execute some command.

class Location < ActiveRecord::Base

def initialize
p 'Tables details'
p Location

p 'Count no of rows in table'
p Location.count
end

end

Location.new

6. Run ruby file from command line, it supposed to display

pravinmishra@ubuntu:~/workSpace/RUBY_CODE/active_record_connection/lib$ ruby main.rb
“Tables details”
Location(name: string, city: string)
“Count no of rows in table”
2

that’s it.

Addition we can separate data configuration in different file and add logger to display sql query OR errors if any. I did all this two setups in active recored connection , You can take a look. 🙂

Cheers!!

Active recored store, rails 3.2


Active Record Store allows us to declare hash keys accessors(inspired by mongoid document oriented data). Any accessor acts like any other attribute of a model. Basically it is used for storing additional attributes within a database record without the need to have to create additional attributes (columns in the database table) to store these values. The contents of these “additional attributes” are stored within the scope of an existing attribute and as serialized as a JSON object. Actually Active Record Store gives you a thin wrapper around serialize for the purpose of storing hashes in a single column. It’s like a simple key/value store backed into your record when you don’t care about being able to query that store outside the context of a single record.

You can then declare accessors to this store that are then accessible just like any other attribute of the model. This is very helpful for easily exposing store keys to a form or elsewhere that’s already built around just accessing attributes on the model.

Make sure that you declare the database column used for the serialized store as a text(not necessary), so there’s plenty of room.

take a look how it works…..

I have addressess table with 3 attributes name,phone and location. I want location as store

class CreateAddresses < ActiveRecord::Migration
  def change
    create_table :addresses do |t|
      t.string :name
      t.integer :phone
      t.string :location

      t.timestamps
    end
  end
end

Now we need to declare location as store within Address model with appropriate keys [ :country, :city, :state ]

class Address < ActiveRecord::Base
    store :location, accessors: [ :country, :city, :state ]
end

Now take a look from console how it initializing object and storing data.

1.9.2p318 :001 > Address.new
=> #<Address id: nil, name: nil, phone: nil, location: {}, created_at: nil, updated_at: nil>
As we can see there is an empty location hash initialized.

1.9.2p318 :002 > address = Address.new
 => #<Address id: nil, name: nil, phone: nil, location: {}, created_at: nil, updated_at: nil>
1.9.2p318 :004 > address.name = ‘Pravin’
 => “Pravin”
1.9.2p318 :006 > address.phone = ‘09749448334’
 => “09749448334”
1.9.2p318 :007 > address.country = ‘india’
 => “india”
1.9.2p318 :008 > address.city = ‘hyderabad’
 => “hyderabad”
1.9.2p318 :009 > address.state = ‘bihar’
 => “bihar”

Any attribute, even if not specified with an accessor

1.9.2p318 :011 > address[:zipcode] = ‘713370’
 => “713370”
1.9.2p318 :012 > address.save
   (0.3ms)  BEGIN
  SQL (60.6ms)  INSERT INTO `addresses` (`created_at`, `location`, `name`, `phone`, `updated_at`) VALUES (‘2012-07-07 02:49:48’, ‘—\n:country: india\n:city: hyderabad\n:state: bihar\n’, ‘Pravin Kumar’, 9749448334, ‘2012-07-07 02:49:48’)
   (102.3ms)  COMMIT
 => true
1.9.2p318 :013 > Address.first
  Address Load (1.3ms)  SELECT `addresses`.* FROM `addresses`
 => #<Address id: 5, name: “Pravin”, phone: 2147483647, location: {:country=>”india”, :city=>”hyderabad”, :state=>”bihar”, :zipcode=>”713370″}, created_at: “2012-07-07 02:55:41”, updated_at: “2012-07-07 02:55:41”>

Screenshot of view.

That’s it….!!!

Eager loading


Eager loading is one of the basic features of Rails but when it’s missing or misused it can lead to huge performance hits because of lazy loading(Lazy loading is a design pattern commonly used in computer programming to defer initialization of an object until the point at which it is needed. It can contribute to efficiency in the program’s operation if properly and appropriately used. The opposite of lazy loading is eager loading.)

Eager loading loads the full objects tree that is the associated records of the objects. When you load records from the database and also want to access the associated objects for each of these records, it’s a good idea to make use of eager loading. Eager loading reduces the amount of queries made to the database and therefor increases performance.

To make use of eager loading, you can use the :include parameter (Rails 2) or the includes method (Rails 3) respectively when doing your ActiveRecord finds.

Consider we have two models Challenge and Task and we have relation like Challenge has many tasks.

Challenge model has the relation has_many :tasks
Task model has the relation belongs_to :challenge

Now lets find all the challenge and its tasks and print the challenge name and task name.

challenges = Challenge.all(:limit => 10)

Next we will iterate through all the challenge and and then get the tasks for that challenge and print the challenge and task name.

challenges.each do |each_challenge|
    puts each_challenge.name
   each_challenge.tasks.each do | each_task |
      puts each_task.name
   end
end

Okay this code works fine, nothing wrong but there is performance issue in this code,
it fires 1 query to find all the challenge and N queries to find the tasks for the challenge.

We can use the includes method provided by Active Record that loads the full objects tree that is the associated records of the objects.

challenges = Challenge.includes(:tasks).limit(10)

challenges.each do |each_challenge|
   puts each_challenge.name
     each_challenge.tasks.each do | each_task |
        puts each_task.name
     end
end

The above code fire 2 queries, one to find all the challenges and the other to find the tasks for the challenges.
This concept is called eager loading, so the challenges variable contains all the challenges and the associated tasks.

That’s it…!!!

Cheers…!!

ruby script for reading the contents of a file and appending in othere file


Content of text file
readdata.txt

Hi, This is Pravin Mishra
Ruby on rails developer
From India

and generating some output based on the content:

readfile.rb


class ReadFile
 
  def execute
    file = File.open(“readdata.txt”)
    contents = []
    all_data = Hash.new
    file.each {|line|
        tokens = line.split(” “)
       
        if tokens.count > 1
            tokens.each_with_index do |data, index|
              all_data[index] = data
            end
            contents << all_data
            all_data = Hash.new
        end
        
        my_file = File.new(“new_file.txt”, “w”)
        my_file.puts contents
    }

  end
 
end

if __FILE__ == $0
  sql = ReadFile.new
  sql.execute
end

Run from the command line as:

> ruby readfile.rb

Out put would be
{0=>”Hi,”, 1=>”This”, 2=>”is”, 3=>”Pravin”, 4=>”Mishra”}
{0=>”Ruby”, 1=>”on”, 2=>”rails”, 3=>”developer”}
{0=>”From”, 1=>”India”}
in new_file.txt

that’s it…!!!