by sandipransing
How to get collection of models inside your application. Certainly there are many ways to do it.
Lets have a look at different ways starting from worst -
Get table names inside database and then iterating over to get model name
@models = ActiveRecord::Base.connection.tables.collect{|t| t.underscore.singularize.camelize}
#=> ["AdhearsionAudit", "AudioLog", "AuditDetail","TinyPrint", "TinyVideo", "UnknownCall", "UserAudit", "User"]
Select those with associated class
@models.delete_if{|m| m.constantize rescue true}
Load models dir
@models = Dir['app/models/*.rb'].map {|f| File.basename(f, '.*').camelize.constantize.name }
Select ActiveRecord::Base extended class only
@models.reject!{|m| m.constantize.superclass != ActiveRecord::Base }
Get Active Record subclasses
# make sure relevant models are loaded otherwise
# require them prior
# Dir.glob(RAILS_ROOT + '/app/models/*.rb').each { |file| require file }
class A < ActiveRecord::Base
end
class B < A
end
ActiveRecord::Base.send(:subclasses).collect(&:name)
#=> [...., A]
How to get Inherited models too
class A < ActiveRecord::Base
end
class B < A
end
ActiveRecord::Base.descendants.collect(&:name)
#=> [...., A, B]
Below is more elegant solution provide by Vincent-robert over stack overflow which recursively looks for subsequent descendent's of class and gives you list from all over application
class Class
def extend?(klass)
not superclass.nil? and ( superclass == klass or superclass.extend? klass )
end
end
def models
Module.constants.select do |constant_name|
constant = eval constant_name
if not constant.nil? and constant.is_a? Class and constant.extend? ActiveRecord::Base
constant
end
end
end
Read More…
by sandipransing
Below extensions to active record base simplifies its usage while coding.
# config/initializers/core_extensions.rb
class ActiveRecord::Base
def self.pagination(options)
paginate :per_page => options[:per_page] || per_page, :page => options[:page]
end
def self.options_for_select(opts={})
opts[:name] ||= :name
opts[:attr] ||= :id
opts[:prompt] ||= 'Please Select'
all.collect{|c| [c.send(opts[:name].to_sym), c.send(opts[:attr].to_sym)]}.insert(0, [opts[:prompt], nil])
end
end
Usage
class Student< ActiveRecord::Base
#attributes #=> name, age
end
##
Student.pagination({:page => 10})
Student.pagination({:per_page => 2, :page => 2})
Student.options_for_select
Student.options_for_select({:prompt => 'Please select'})
Student.options_for_select({:name => :age})
Read More…
by sandipransing
Scopes are partial query conditions to database queries. scopes are always prefixed to class finders. There are several ways to use scopes inside rails models.
# 1. Scope defined below gets loaded while class definition loads
scope :active, where(:active => true)
scope :archived, where(:archived => true, :post_type => :general)
# 2.Dynamic scopes needs to be always defined inside lambda
scope :not_expired, lambda { where('expiry_date <= ?', Date.today) }
# 3.Combining scopes
scope :visible, published.not_expired
# 4. Passing parameters to scopes
# avoid below
scope :created_by_user, lambda {|user|
where('user_id = ?', user)
}
# use this
scope :created_by_user, lambda {|user|
where(:user_id => user)
}
# 5. passing multiple parameters
# avoid below
scope :made_between, lambda{|from, to|
where('created_date >= ? and created_date <= ?', from, to)
}
# use this
scope :made_between, lambda{|from, to|
where('created_date >= :from and created_date <= :to', :from => from, :to => to)
}
# 6. associations inside scope (joins and includes)
# below will perform eager loading effective when rendering posts with comments
scope :with_user_comments, lambda{|user|
includes(:comments).where('comments.user_id = ?', user)
}
# faster
# also can be done as post.comments.where(:user_id => user)
scope :with_user_comments, lambda{|user|
joins(:comments).where('comments.user_id = ?', user)
}
So, at last would suggest making use of symbols when there are multiple parameters to scopes and make maximum use of scopes rather than having where conditions everywhere :)
Read More…
by sandipransing
While developing rails application we often come across situation where you wanted different rails models connecting different tables of different databases.
Example: We are having ndnc model holding ndnc records associated with database ndnc.
Lets create ConnectionBase model that will connect to other databse 'ndnc' and that will be extended from ActiveRecordBase and put that inside library files
vi lib/connection_base.rb
class ConnectionBase < ActiveRecord::Base
establish_connection(
:adapter => "postgresql",
:username=> "sandip",
:password => "2121",
:database => "ndnc"
)
end
Wherever you wanted to connect to other database i.e. ndnc you can extend that particular model with ConnectionBase
class Ndnc < ConnectionBase
# connects to ndnc table of ndnc database
end
Please make sure library files are loaded while server startup
# vi config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
Done !
In cases where you want only one particular model connecting other database table, you can put connection setting itself in that model.
Read More…
by sandipransing
ActiveRecord find with join options retrieves object as readonly
station = Station.find( :first, :joins => :call, :conditions => ["customer_id = ? and date(insurance_expiry_date) = ?", customer.id, insurance_expiry_date ] )
Readonly object cannot modified and hence below line raises "ActiveRecord::ReadOnlyRecord" error.
station.update_attributes({ :customer_id => 12 })
If you have to write on read only object then you can pass following option to find query
:readonly => false
Now below find is permitted to do write on fetched object records.
station = Station.find( :first, :joins => :call, :conditions => ["customer_id = ? and date(insurance_expiry_date) = ?", customer.id, insurance_expiry_date ], :readonly => false )
Read More…
by sandipransing
I have Site Model and i wanted to find all associated models of Site model which are having
belongs_to relationship.
After doing lot headache, here is the solution i found
has_many models of Site Model
Site.reflect_on_all_associations.map{|mac| mac.class_name if mac.macro==:has_many}.compact
=> ["Layout", "User", "SubmenuLink", "Snippet", "Asset"]
belongs_to model of Site Model
Site.reflect_on_all_associations.map{|mac| mac.class_name if mac.macro==:belongs_to}.compact
=> ["User", "Page", "User"]
To get all associations
Site.reflect_on_all_associations.map{|mac| mac.class_name}.compact
=> ["Layout", "User", "Page", "User", "SubmenuLink", "User", "Snippet", "Asset"]
Hari, U rocks !
Read More…
by sandipransing
Below is ruby code to establish manual database connection.
require 'active_record'
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "localhost",
:username => "root",
:password => "abcd",
:database => "funonrails"
)
Snippet of database.yml file
common: &common
adapter: mysql
database: students_dev
username: root
password:
host: localhost
students_development:
<<: *common
database: students_dev
students_production:
<<: *common
database: students
Load database configurations from yml file
dbconfig = YAML::load(File.open('database.yml'))
ActiveRecord::Base.establish_connection( dbconfig[:students_development] )
Active Record Model & DB connection
class Student < ActiveRecord::Base
establish_connection "students_production"
set_table_name "student"
set_primary_key "stud_number"
end
Read More…
by sandipransing
Rails specifies conventions while creating models, controllers, migrations ( database tables ).
Conventions for creating database tables
1. Table name should be plural
2. id field should be primary_key for table.
3. foreign_key should be like _id i.e. post_id, site_id
Conventions for creating models & Controllers
1. Model name should be singular
2. controller name should be plural.
Although rails has standard defined, In some cases it becomes quite necessary to map irregular
1. Table mapping
class Review < ActiveRecord::Base
# Here comments is name of database table
set_table_name :comments
end
2. Set primary key ( other than rails standar 'id' primary_key )
class Review < ActiveRecord::Base
# It assumes "reviews" as table in database
# Below line indicates reviews table contains column_name "reviewId" which is a primary_key
set_primary_key :reviewId
end
3. Foreign key association
class Review < ActiveRecord::Base
# Below line indicates reviews table contains column_name 'RatingId' which is foreign_key to primary_key
# of 'ratings' table.
# It can be applied to any associan type [ has_one, has_many, belongs_to, has_many_through ]
belongs_to :rating, :class_name => "SiteUser", :foreign_key => "RatingId"
end
4. Model association ( non-standard model name )
class Review < ActiveRecord::Base
# Below line indicates reviews table contains column_name 'UserId' which is foreign_key to primary_key
# of model with class_name 'SiteUser'
belongs_to :user, :class_name => 'SiteUser', :foreign_key: => 'UserId'
end
Read More…
|