Recent good notes
RSS feedApplication Helper for Fading Flash Messages
A simple helper method for showing the flash message. Includes optional fade in seconds (view needs javascript_include_tag defaults if you desire fade effect):
def show_flash_message(options={}) html = content_tag(:div, flash.collect{ |key,msg| content_tag(:div, msg, :class => key) }, :id => 'flash-message') if options.key?(:fade) html << content_tag(:script, "setTimeout(\"new Effect.Fade('flash-message');\",#{options[:fade]*1000})", :type => 'text/javascript') end html end
simply call in your views then using:
<%= show_flash_message(:fade => 4) %>
Customizing attribute names in error messages
By default, the error messages translate the names of the attributes through String#humanize. The way to to change that is to override the ActiveRecord::Base.human_attribute_name method. For example, if you want to name a column in your database as <tt>:www_url</tt> and you want to say "Website" instead of "Www url" in the error message, you can put this into your model: class Person < ActiveRecord::Base def self.human_attribute_name(attribute_key_name) if attribute_key_name.to_sym == :www_url "Website" else super end end end Currently this seems to be the cleanest and easiest way. Unfortunately, human_attribute_name is deprecated and may stop working in a future release of Rails.List of status codes and their symbols
Note that the :status option accepts not only an HTTP status code (such as 500), but also a symbol representing that code (such as :created), if that makes more sense to you. Here's a list of which symbols map to which numbers (derived from ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE):
100 = :continue 101 = :switching_protocols 102 = :processing 200 = :ok 201 = :created 202 = :accepted 203 = :non_authoritative_information 204 = :no_content 205 = :reset_content 206 = :partial_content 207 = :multi_status 226 = :im_used 300 = :multiple_choices 301 = :moved_permanently 302 = :found 303 = :see_other 304 = :not_modified 305 = :use_proxy 307 = :temporary_redirect 400 = :bad_request 401 = :unauthorized 402 = :payment_required 403 = :forbidden 404 = :not_found 405 = :method_not_allowed 406 = :not_acceptable 407 = :proxy_authentication_required 408 = :request_timeout 409 = :conflict 410 = :gone 411 = :length_required 412 = :precondition_failed 413 = :request_entity_too_large 414 = :request_uri_too_long 415 = :unsupported_media_type 416 = :requested_range_not_satisfiable 417 = :expectation_failed 422 = :unprocessable_entity 423 = :locked 424 = :failed_dependency 426 = :upgrade_required 500 = :internal_server_error 501 = :not_implemented 502 = :bad_gateway 503 = :service_unavailable 504 = :gateway_timeout 505 = :http_version_not_supported 507 = :insufficient_storage 510 = :not_extended
Ruby's exception hierarchy
Ruby's exception hierarchy, according to http://blog.nicksieger.com/articles/2006/09/06/rubys-exception-hierarchy:
NoMemoryError ScriptError LoadError NotImplementedError SyntaxError SignalException Interrupt StandardError ArgumentError IOError EOFError IndexError LocalJumpError NameError NoMethodError RangeError FloatDomainError RegexpError RuntimeError SecurityError SystemCallError SystemStackError ThreadError TypeError ZeroDivisionError SystemExit fatal
Implemented in database adapters
These methods are not implemented in the abstract classes. Instead, all database adapters implement these separately, if the feature is supported.
Rendering nothing
If your controller action does not explicitly call render, Rails will, by default, attempt to locate and render the template corresponding to the action. It's not uncommon, for example with Ajax calls, to want to render nothing. This will circumvent the default rendering and prevent errors on missing templates. To render nothing simply do the following:
render :nothing => true
Its important to note that this isn't the same as returning no HTTP response. In fact, this results in an HTTP response with a status code of 200 OK being sent back with a blank content body. Why does it matter? Well, you can still test your controller by asserting that a :success response was returned.
Link to caller URL
link_to "Back", :back
Documentation for Associations
You are most likely looking for ActiveRecord::Associations::ClassMethods
Pass the observed fields value as a parameter in the Ajax request
Use encodeURIComponent with with to pass an encoded value as a parameter (POST or GET) of the AJAX request. For example:
<%= observe_field :company_id, :url => {:action => 'facilities', :only_path => false}, :with => "'company=' + encodeURIComponent(value)" %>
Also, setting only_path => false for the URL ensures that the full URL (including host and protocol) is used for the AJAX request.
All methods
create_table :table do |t| t.column # adds an ordinary column. Ex: t.column(:name, :string) t.index # adds a new index. t.timestamps t.change # changes the column definition. Ex: t.change(:name, :string, :limit => 80) t.change_default # changes the column default value. t.rename # changes the name of the column. t.references t.belongs_to t.string t.text t.integer t.float t.decimal t.datetime t.timestamp t.time t.date t.binary t.boolean t.remove t.remove_references t.remove_belongs_to t.remove_index t.remove_timestamps end
All methods
change_table :table do |t| t.column # adds an ordinary column. Ex: t.column(:name, :string) t.index # adds a new index. t.timestamps t.change # changes the column definition. Ex: t.change(:name, :string, :limit => 80) t.change_default # changes the column default value. t.rename # changes the name of the column. t.references t.belongs_to t.string t.text t.integer t.float t.decimal t.datetime t.timestamp t.time t.date t.binary t.boolean t.remove t.remove_references t.remove_belongs_to t.remove_index t.remove_timestamps end
print standard-looking messages during migration
Within a migration file you can use the say_with_time method to print out informational messages that match the style of standard migration messages. See the say method also.
say_with_time "migrate existing data" do # ... execute migration sql ... end #=> "-- migrate existing data" #=> " -> 0.0299s"
Readable strftime
%a - The abbreviated weekday name (``Sun'')
%A - The full weekday name (``Sunday'')
%b - The abbreviated month name (``Jan'')
%B - The full month name (``January'')
%c - The preferred local date and time representation
%d - Day of the month (01..31) %H - Hour of the day, 24-hour clock (00..23)
%I - Hour of the day, 12-hour clock (01..12)
%j - Day of the year (001..366)
%m - Month of the year (01..12) %M - Minute of the hour (00..59)
%p - Meridian indicator (``AM'' or ``PM'')
%S - Second of the minute (00..60)
%U - Week number of the current year, starting with the first Sunday as the first day of the first week (00..53)
%W - Week number of the current year, starting with the first Monday as the first day of the first week (00..53)
%w - Day of the week (Sunday is 0, 0..6)
%x - Preferred representation for the date alone, no time
%X - Preferred representation for the time alone, no date
%y - Year without a century (00..99) %Y - Year with century
%Z - Time zone name %% - Literal ``%’’ character t = Time.now t.strftime("Printed on %m/%d/%Y") #=> "Printed on 04/09/2003" t.strftime("at %I:%M%p") #=> "at 08:56AM"
Custom collection local variable name
Regarding the previous note from hoodow about using :variable_name to create a custom local variable name when rendering a collection with a partial, the argument should be :as instead of :variable_name, so:
render :partial => "video_listing", :collection => @recommendations, :as => :video
Useful in migrations
The most common usage pattern for this method is probably in a migration, when just after creating a table you want to populate it with some default values, eg: class CreateJobLevels < ActiveRecord::Migration def self.up create_table :job_levels do |t| t.integer :id t.string :name t.timestamps end JobLevel.reset_column_information %w{assistant executive manager director}.each do |type| JobLevel.create(:name => type) end end def self.down drop_table :job_levels end endAlways pass a block
I highly recommend always taking a block and passing it back up the chain if you use alias_method_chain, even if the original method does not. Otherwise you're keeping anyone later in the chain from adding support for blocks.
http://tech.hickorywind.org/articles/2008/08/29/always-pass-a-block-when-using-alias_method_chain
Get year to show in descending order (Today to 1920 for example)
The way people think of time start and end would be 1920 to today. This made me think "but I want it show the current year first then down." Well it's as simple as swapping the start_year and end_year.
date_select :date, :start_year => Date.current.year, :end_year => 1920 # => 2008, 2007, 2006, 2005 ... 1920
Only attr_accessible attributes will be updated
If your model specified attr_accessible attributes, only those attributes will be updated.
Use attr_accessible to prevent mass assignment (by users) of attributes that should not be editable by a user. Mass assignment is used in create and update methods of your standard controller.
For a normal user account, for example, you only want login and password to be editable by a user. It should not be possible to change the status attribute through mass assignment.
class User < ActiveRecord::Base attr_accessible :login, :password end
So, doing the following will merrily return true, but will not update the status attribute.
@user.update_attributes(:status => 'active')
If you want to update the status attribute, you should assign it separately.
@user.status = 'active' save
Rake tasks for gem dependencies
You can manage installation and other tasks for these dependencies with rake tasks, for example:
rake gems:install # Installs all required gems for this application rake gems:unpack # Unpacks the specified gem into vendor/gems
To get all rake tasks about gems:
rake -T gems
Doesn't add an index
Typically you will want to have an index on foreign keys but this method doesn't assume that. Outside of the create_table block you should follow this with add_index :
add_index :table_name, :goat_id # and, if polymorphic: add_index :table_name, :goat_type
Specifying :include no longer necessarily joins the association
Before Rails 2.1, adding an :include=>[:association] in your find method caused ActiveRecord to generate SQL using a join. Since 2.1, it MAY NOT execute as a join.
The join executes a large query and returned potentially duplicate records for a one-to-many association. After 2.1, the query is broken down and eager-loaded using an additional query per association, passing the set of id's to load, and avoiding the duplicate rows.
The new method eliminates duplicates, but can incur more database overhead. If you are loading a very large set of records (more than a "page"), you may need to "force" the join or use find_by_sql instead.
When you specify a "table.column" syntax within a
:conditions=>["child.name=?", name]
or
:order=>'child.name'
then ActiveRecord will build the older, full query with the join because you are referencing columns from another table to build. This will cause the duplicate rows to reappear.
Whenever you reference a column from another table in a condition or order clause, ALWAYS use the table name to prefix the column, even if it not ambiguous among the tables involved. Otherwise the query will not be executed as a join and you will receive an SQL error referencing the "missing" column.
You can "force" a join by adding a reference to the other tables in your :conditions or :options parameters, even if the test or sort is irrelevant.
Iterate and join blocks
Following LacKac's idea, we can write render_join (useful to render a collection with a small chunks of code, where a render :partial + :spacer_template would be overkill):
def render_join(collection, join_string, &block) output = collection.collect do |item| capture(item, &block) end.join(join_string) concat(output, block.binding) end
An example of use:
<% render_join(@items, '<br />') do |item| %> <p>Item title: <%= item.title %></p> <% end %>
preload_associations manually
Usually you preload associations using <tt>:include => [ ... ]</tt>. In Rails 2.1 each association is fetched with a separate query. Something like: <tt>Post.find(:all, :include => [:tags, :user])</tt> will produce 3 queries - each for posts, tags and users. --- But sometimes you have a complex query, which uses <tt>:joins => :other_association</tt> and conditions between multiple tables, but not the ones you need to include. Then everything is mixed back in one query like in old versions of Rails. Another case may be when it is not possible to use <tt>:include</tt> at all, for example while using <tt>find_by_sql</tt>, but you still want/need to preload associated records. In rails 2.1 <tt>find</tt> uses <tt>preload_associations</tt> internally, when it is possible (There are no joins or conditions between tables). So then you can preload asociations manually from within your model: <tt>class Post < ActiveRecord::Base</tt> has_many :tags belongs_to :user ... def self.find_complex_with_includes posts = find_by_sql(...) # or find(:all, :joins => .....) preload_associations(posts, [:tags, :user]) posts end <tt>end</tt> and then do <tt>@posts = Post.find_complex_with_includes</tt>Namespace or modules in routes
If you have grouped controllers into a module, e.g. admin then you can specify this in the routes using the namespace method:
map.namespace :admin do |admin| admin.resources :categories end
which will map the categories resource giving urls like
/admin/categories/
/admin/categories/new
It will also generate the named routes such as new_admin_category_url and admin_category_path
script/generate syntax
To add a post_id field to a comments table, run this: script\generate migration add_post_id_to_comment post_id:integer See that it´s not the table name(plural), but the model name(singular),<br /> and post_id:references, does not works like in create_table. This is the generated migration: class AddPostIdToComment < ActiveRecord::Migration def self.up add_column :comments, :post_id, :integer end def self.down remove_column :comments, :post_id end endRegexes with groups and split
When you use a Regex with capture groups, all capture groups are included in the results (interleaved with the "real" results) but they do not count for the limit argument.
Examples:
"abc.,cde.,efg.,ghi".split(/.(,)/) => ["abc", ",", "cde", ",", "efg", ",", "ghi"] "abc.,cde.,efg.,ghi".split(/(.)(,)/) => ["abc", ".", ",", "cde", ".", ",", "efg", ".", ",", "ghi"] "abc.,cde.,efg.,ghi".split(/(.(,))/) => ["abc", ".,", ",", "cde", ".,", ",", "efg", ".,", ",", "ghi"] "abc.,cde.,efg.,ghi".split(/(.(,))/, 2) => ["abc", ".,", ",", "cde.,efg.,ghi"] "abc.,cde.,efg.,ghi".split(/(.(,))/, 3) => ["abc", ".,", ",", "cde", ".,", ",", "efg.,ghi"]
Using sweepers in script/runner
If you need to use some of your sweepers in a script/runner script or some rake task you can use this snipped:
require 'action_controller/test_process' sweepers = [ProductSweeper, UserSweeper] ActiveRecord::Base.observers = sweepers ActiveRecord::Base.instantiate_observers controller = ActionController::Base.new controller.request = ActionController::TestRequest.new controller.instance_eval do @url = ActionController::UrlRewriter.new(request, {}) end sweepers.each do |sweeper| sweeper.instance.controller = controller end
Your script will fire the ActiveRecord callbacks defined in that sweepers and you can use expire_cache, expire_fragment and also the routing helpers you have defined (hash_for_user_path, hash_for_product_path, etc.).
Explanation about :dependent option
It may seem that :dependent option is only used when the object that has the collection is destroyed, but it is also used every time a associated object is deleted, so if you use
object.collection.delete(associated_object)
your object will be deleted, destroyed or nullified, depending on the value of :dependent option.
With has_many :through associations this option is ignored at least in versions up to 2.1.0, so even if you set :dependent option to :destroy, your join objects will be deleted, not firing any callbacks you have set on destroy events.
If you need to act when your join model is deleted you can use a sweeper or an observer and the association callbacks like this:
# product.rb class Product has_many :categorizations has_many :categories, :through => :categorizations, :before_remove => :fire_before_remove_in_categorizations private def fire_before_remove_in_categorizations(category) categorization = self.categorizations.find_by_category_id(category.id) categorization.class.changed categorization.class.notify_observers(:before_remove, categorization) end end # categorization_sweeper.rb # do not forget to load this sweeper during initialization class CategorizationSweeper < ActionController::Caching::Sweeper observe Categorization def before_remove(categorization) # expire_cache, expire_fragment, whatever end end
One thing you should be aware of it is that you are using before_remove, so you have to be careful because your record may be not be removed (another callback raising an exception or the database not deleting the record) so you can not be sure your object will be delete. Expiring caches is safe because even if your record is not destroyed your cache will be regerated correctly.
You can not use after_remove, because at that point the join model do not exists anymore, so you can not fire its callbacks. But you have the model id and the associated model id, so if you do not need expiring caches maybe you can use this approach (expiring caches can be only done in a sweeper or in a controller, but with after_remove you are bound to your model).

