Ruby on Rails: active record activerecord birthdays cache counter datetime how to scopes timestamp
by bseanvt
leave a comment
Rails Find All by Birthday: How to Find Upcoming Birthdays with ActiveRecord
There are a few ways to solve this problem. However, I think the easiest is to cache the day of the year that the user is born on as an integer. If stored alongside the timestamp we can quickly get a list but properly handle the full birthday elsewhere, such as in the view. You don’t want to rely on just the cached day of year because leap year is not accounted for.
The model will need both born_at and birthday columns.
create_table :users do |t| t.timestamp :born_at # full timestamp t.integer :birthday # just the day of year end
The user model also needs a callback (before_save) to set and or update the cached birthday column based on the full timestamp. For convenience, a named scope can be added to the model which will let you call User.birthdays.
class User
# User.birthdays
scope :birthdays, lambda { where('birthday in(?)', 7.times.map{|i| Time.now.yday + i}) }
def before_save
self.birthday = born_at.yday
end
end
You could also use the week in year (1 – 52) for the cache. Using the day you can look an arbitrary number of days ahead.
Ruby on Rails: active record models named scopes scopes
by bseanvt
leave a comment
Reusing Scopes (Formerly Named_scope) In Rails 3
You can easily chain scopes together in your models.
class Article < ActiveRecord::Base
scope :ordered, order('position ASC')
scope :published, ordered.where('published = ?', true)
scope :for_homepage, published.limit(3)
end
Article.for_homepage.to_sql
# => SELECT \"articles\".* FROM \"articles\" WHERE (published = 't') ORDER BY position LIMIT 3
Programming Ruby on Rails: active record classify constants initialize load models rake Ruby on Rails
by bseanvt
leave a comment
Load All ActiveRecord::Base Model Classes in Rails Application
Here is a simple rake task which will instantiate all of your Active Record models, provided that they are located in the RAILS_ROOT/app/models directory. Interestingly, all plugin models are instantiated by default when you run the task, for instance, if you are using the Acts As Taggable On plugin, you have access to Tag, Tagging without having to include the plugin models directory path to the task.
namespace :load_ar do
desc "load up all active record models"
task :models => :environment do
models = ActiveRecord::Base.send(:subclasses)
Dir["#{RAILS_ROOT}/app/models/*"].each do |file|
model = File.basename(file, ".*").classify
models << model unless models.include?(model)
end
end
end
If your’re in the console, you can get all the load paths for your Active Record models with the following from the API.
Rails.configuration.load_paths.each do |path| p path end
Rake DB Everything, Dump, Destroy, Create, Load
I’m a big fan of the yaml_db plugin. But I don’t like running rake db:data:load, only to find that my db columns mismatch my model attributes, thus aborting the data import task. To quickly add/remove columns/attributes from a model and rebuild the database with previous db info, I wrote this simple rake task. It saves model records as yaml in db/seandb.yml, and reloads them in the same task but with the db rebuilt. I nest the save method in begin/rescue so that if there are any conflicts the task will continue.
This biggest challenge was to get a list of all the active record models in the Rails app. This problem has been posted a lot and I didn’t find an easy solution. For now, I just look in the app/models directory and ‘classify’ and ‘constantize’ the file name. This will load the model so that I can iterate over all the active record subclasses and call the appropriate Model.find(:all) method. I could maybe do the same w/ all files in the Rails.configuration.load_paths, but my models are, at least for now, under app/models. Plugin models are loaded and available from the rake task if you require the :environment.
It’s as simple as running
rake db:everything
SAVEDB = "#{RAILS_ROOT}/db/seandb.yml"
namespace :db do
task :everything => [:environment, :spit, :drop, :create, :migrate, :populate] do
desc "spit out model records as yaml, rebuild the database and repopulate the db"
end
task :spit do
Dir["#{RAILS_ROOT}/app/models/*"].each {|file| (File.basename(file,".*").classify.constantize)}
File.open(SAVEDB, "w") do |f|
ActiveRecord::Base.send(:subclasses).each do |model|
begin
model.find(:all).each do |record|
f.write(record.to_yaml)
print "\twrote #{record.class}\n"
end
rescue
end
end
end
end
task :populate do
File.open( SAVEDB ) do |yf|
YAML.each_document( yf ) do |ydoc|
begin
m = ydoc.clone
m.save
p "...saved #{m.id}"
rescue
end
end
end
end
end
Active Record Find Methods
Active Record find methods for selecting range from http://charlesmaxwood.com/notes-from-reading-activerecordbase/
Student.find(:all, :conditions => { :grade => 9..12 })
return a range
Student.find(:all, :conditions => { :grade => [9,11,12] })
will return an "in()"
Ruby on Rails: active record override password validations
by bseanvt
leave a comment
Change database column names for form validations in Rails
When you use validations in Rails, db column names are used as ‘keys’ for error messages. This is usually the preferred way to go about it because this maps nicely to the form fields. However, if you use a virtual attribute this may not be the case. For example, I have a ‘password_crypted’ field in my users table that I don’t want my user to see if they fail to complete the field. Instead of returning “Password crypted cannot be blank” I just want to tell them that a password can’t be blank. If you provide a custom ‘:message’ on the validation this won’t replace the column name. The solution is to override the “human_attribute_name” class method and map specific column names to the string you want to use instead.
class User < ActiveRecord::Base
validates_presence_of :password_crypted
ATTR_NAMES = {:password_crypted => "Password"}
def self.human_attribute_name(attr)
ATTR_NAMES[attr.to_sym] || super
end
end
I found these resources helpful while I was in search for a solution to this problem.
http://stackoverflow.com/questions/808547/fully-custom-validation-error-message-with-rails
http://henrik.nyh.se/2007/12/change-displayed-column-name-in-rails-validation-messages
Ruby on Rails: active record migration model plugins tags
by bseanvt
leave a comment
Rails Plugin Acts as Taggable on Steriods
You can download it here http://github.com/suitmymind/acts-as-taggable-on-steroids as well as read usage info (which is for the most part reprinted here).
./script/plugin install http://svn.viney.net.nz/things/rails/plugins/acts_as_taggable_on_steroids ./script/generate acts_as_taggable_migration rake db:migrate
Then in your model
class Post < ActiveRecord::Base
acts_as_taggable
end
And usage is as follows
p = Post.find(:first)
p.tag_list # []
p.tag_list = "Funny, Silly"
p.save
p.tag_list # ["Funny", "Silly"]
p.tag_list.add("Great", "Awful")
p.tag_list.remove("Funny")
#to find...
Post.find_tagged_with('Funny, Silly')
Post.find_tagged_with('Funny, Silly', :match_all => true)
To use this in a form and let users enter a comma separated list of tag names…
form_for @post do |f| f.text_field :tag_list
And to get a tag cloud
#controller
class PostController < ApplicationController
def tag_cloud
@tags = Post.tag_counts
end
end
# and in view...
<style>
.css1 { font-size: 1.0em; }
.css2 { font-size: 1.2em; }
.css3 { font-size: 1.4em; }
.css4 { font-size: 1.6em; }
</style>
<% tag_cloud @tags, %w(css1 css2 css3 css4) do |tag, css_class| %>
<%= link_to tag.name, { :action => :tag, :id => tag.name }, :class => css_class %>
<% end %>
*Note. If you have a controller “tags_controller.rb” and the auto generated (if you used ./script/generate) helper file “tags_helper.rb” you’ll need to make sure to copy the contents of the plugin lib module of the same name, into the helper file. You’ll get an error otherwise.
Ruby on Rails: active record array created_at sort_by
by bseanvt
leave a comment
Descending Sort By in Model For Active Record Hash on Created_at attribute
If you have a couple collections from the database and you want to sort it without the help of Active Record, take a look at the sort_by method on Array type. I’ve used this before when I have a couple of collections which are slightly different but I need them in a chronological order.
@posts_group_a = Post.find :all, :conditions => ["user_id = ?", current_user.id]
@posts_group_b = Post.find :all, :conditions => ["user_id = ?", friend_user.id]
#merge the two arrays here
@posts = @posts_group_a + @posts_group_b
# notice the "-" is for descending order and the "to_i" casts the date time to an integer (required)
@posts.sort_by {|post| - post.created_at.to_i}
Ruby on Rails: active record console development logging stdout
by bseanvt
1 comment
Output Logger and SQL to the Rails Console in Development Mode
If you want to take a look at the SQL being generated by active record while your using the console, you can either type this into the console when it loads
ActiveRecord::Base.logger = Logger.new(STDOUT)
Or you can add it to your environment so that it’ll be the default behavior
rails_root/config/environments/development.rb
#... ActiveRecord::Base.logger = Logger.new(STDOUT)
It’s a nice way to keep you away of any expensive queries you may unknowingly be writing!


